diff --git a/Assets/Cinematic Effects/AmbientOcclusion.meta b/Assets/Cinematic Effects/AmbientOcclusion.meta new file mode 100644 index 0000000..d6631d6 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ed6d7947a564a4dd1987f60392be4349 +folderAsset: yes +timeCreated: 1457326591 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs new file mode 100644 index 0000000..c3808f9 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs @@ -0,0 +1,347 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Ambient Occlusion")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public partial class AmbientOcclusion : MonoBehaviour + { + #region Public Properties + + /// Effect settings. + [SerializeField] + public Settings settings = Settings.defaultSettings; + + /// Checks if the ambient-only mode is supported under the current settings. + public bool isAmbientOnlySupported + { + get { return targetCamera.hdr && isGBufferAvailable; } + } + + #endregion + + #region Private Properties + + // Properties referring to the current settings + + float intensity + { + get { return settings.intensity; } + } + + float radius + { + get { return Mathf.Max(settings.radius, 1e-4f); } + } + + SampleCount sampleCount + { + get { return settings.sampleCount; } + } + + int sampleCountValue + { + get + { + switch (settings.sampleCount) + { + case SampleCount.Lowest: return 3; + case SampleCount.Low: return 6; + case SampleCount.Medium: return 12; + case SampleCount.High: return 20; + } + return Mathf.Clamp(settings.sampleCountValue, 1, 256); + } + } + + bool downsampling + { + get { return settings.downsampling; } + } + + bool ambientOnly + { + get { return settings.ambientOnly && isAmbientOnlySupported; } + } + + // AO shader + Shader aoShader + { + get + { + if (_aoShader == null) + _aoShader = Shader.Find("Hidden/Image Effects/Cinematic/AmbientOcclusion"); + return _aoShader; + } + } + + [SerializeField] Shader _aoShader; + + // Temporary aterial for the AO shader + Material aoMaterial + { + get + { + if (_aoMaterial == null) + _aoMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(aoShader); + return _aoMaterial; + } + } + + Material _aoMaterial; + + // Command buffer for the AO pass + CommandBuffer aoCommands + { + get + { + if (_aoCommands == null) + { + _aoCommands = new CommandBuffer(); + _aoCommands.name = "AmbientOcclusion"; + } + return _aoCommands; + } + } + + CommandBuffer _aoCommands; + + // Target camera + Camera targetCamera + { + get { return GetComponent(); } + } + + // Property observer + PropertyObserver propertyObserver { get; set; } + + // Check if the G-buffer is available + bool isGBufferAvailable + { + get + { + var path = targetCamera.actualRenderingPath; + return path == RenderingPath.DeferredShading; + } + } + + // Reference to the quad mesh in the built-in assets + // (used in MRT blitting) + Mesh quadMesh + { + get { return _quadMesh; } + } + + [SerializeField] Mesh _quadMesh; + + #endregion + + #region Effect Passes + + // Build commands for the AO pass (used in the ambient-only mode). + void BuildAOCommands() + { + var cb = aoCommands; + + var tw = targetCamera.pixelWidth; + var th = targetCamera.pixelHeight; + var ts = downsampling ? 2 : 1; + var format = RenderTextureFormat.R8; + var rwMode = RenderTextureReadWrite.Linear; + var filter = FilterMode.Bilinear; + + // AO buffer + var m = aoMaterial; + var rtMask = Shader.PropertyToID("_OcclusionTexture"); + cb.GetTemporaryRT(rtMask, tw / ts, th / ts, 0, filter, format, rwMode); + + // AO estimation + cb.Blit((Texture)null, rtMask, m, 0); + + // Blur buffer + var rtBlur = Shader.PropertyToID("_OcclusionBlurTexture"); + + // Primary blur filter (large kernel) + cb.GetTemporaryRT(rtBlur, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.right * 2); + cb.Blit(rtMask, rtBlur, m, 1); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * 2 * ts); + cb.Blit(rtBlur, rtMask, m, 1); + cb.ReleaseTemporaryRT(rtBlur); + + // Secondary blur filter (small kernel) + cb.GetTemporaryRT(rtBlur, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.right * ts); + cb.Blit(rtMask, rtBlur, m, 2); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * ts); + cb.Blit(rtBlur, rtMask, m, 2); + cb.ReleaseTemporaryRT(rtBlur); + + // Combine AO to the G-buffer. + var mrt = new RenderTargetIdentifier[] { + BuiltinRenderTextureType.GBuffer0, // Albedo, Occ + BuiltinRenderTextureType.CameraTarget // Ambient + }; + cb.SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget); + cb.SetGlobalTexture("_OcclusionTexture", rtMask); + cb.DrawMesh(quadMesh, Matrix4x4.identity, m, 0, 4); + + cb.ReleaseTemporaryRT(rtMask); + } + + // Execute the AO pass immediately (used in the forward mode). + void ExecuteAOPass(RenderTexture source, RenderTexture destination) + { + var tw = source.width; + var th = source.height; + var ts = downsampling ? 2 : 1; + var format = RenderTextureFormat.R8; + var rwMode = RenderTextureReadWrite.Linear; + + // AO buffer + var m = aoMaterial; + var rtMask = RenderTexture.GetTemporary(tw / ts, th / ts, 0, format, rwMode); + + // AO estimation + Graphics.Blit((Texture)null, rtMask, m, 0); + + // Primary blur filter (large kernel) + var rtBlur = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.right * 2); + Graphics.Blit(rtMask, rtBlur, m, 1); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * 2 * ts); + Graphics.Blit(rtBlur, rtMask, m, 1); + RenderTexture.ReleaseTemporary(rtBlur); + + // Secondary blur filter (small kernel) + rtBlur = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.right * ts); + Graphics.Blit(rtMask, rtBlur, m, 2); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * ts); + Graphics.Blit(rtBlur, rtMask, m, 2); + RenderTexture.ReleaseTemporary(rtBlur); + + // Combine AO with the source. + m.SetTexture("_OcclusionTexture", rtMask); + + if (!settings.debug) + Graphics.Blit(source, destination, m, 3); + else + Graphics.Blit(source, destination, m, 5); + + RenderTexture.ReleaseTemporary(rtMask); + } + + // Update the common material properties. + void UpdateMaterialProperties() + { + var m = aoMaterial; + m.shaderKeywords = null; + + m.SetFloat("_Intensity", intensity); + m.SetFloat("_Radius", radius); + m.SetFloat("_TargetScale", downsampling ? 0.5f : 1); + + // Use G-buffer if available. + if (isGBufferAvailable) + m.EnableKeyword("_SOURCE_GBUFFER"); + + // Sample count + if (sampleCount == SampleCount.Lowest) + m.EnableKeyword("_SAMPLECOUNT_LOWEST"); + else + m.SetInt("_SampleCount", sampleCountValue); + } + + #endregion + + #region MonoBehaviour Functions + + void OnEnable() + { + // Check if the shader is supported in the current platform. + if (!ImageEffectHelper.IsSupported(aoShader, true, false, this)) + { + enabled = false; + return; + } + + // Register the command buffer if in the ambient-only mode. + if (ambientOnly) + targetCamera.AddCommandBuffer(CameraEvent.BeforeReflections, aoCommands); + + // Requires DepthNormals when G-buffer is not available. + if (!isGBufferAvailable) + targetCamera.depthTextureMode |= DepthTextureMode.DepthNormals; + } + + void OnDisable() + { + // Destroy all the temporary resources. + if (_aoMaterial != null) DestroyImmediate(_aoMaterial); + _aoMaterial = null; + + if (_aoCommands != null) + targetCamera.RemoveCommandBuffer(CameraEvent.BeforeReflections, _aoCommands); + _aoCommands = null; + } + + void Update() + { + if (propertyObserver.CheckNeedsReset(settings, targetCamera)) + { + // Reinitialize all the resources by disabling/enabling itself. + // This is not very efficient way but just works... + OnDisable(); + OnEnable(); + + // Build the command buffer if in the ambient-only mode. + if (ambientOnly) + { + aoCommands.Clear(); + BuildAOCommands(); + } + + propertyObserver.Update(settings, targetCamera); + } + + // Update the material properties (later used in the AO commands). + if (ambientOnly) UpdateMaterialProperties(); + } + + [ImageEffectOpaque] + void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (ambientOnly) + { + // Do nothing in the ambient-only mode. + Graphics.Blit(source, destination); + } + else + { + // Execute the AO pass. + UpdateMaterialProperties(); + ExecuteAOPass(source, destination); + } + } + + #endregion + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta new file mode 100644 index 0000000..30be0c0 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/AmbientOcclusion.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e89654dcf6db746d2a57aeaaa14f5e83 +timeCreated: 1457327177 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _aoShader: {fileID: 4800000, guid: 65e203e5acda447acbf9dc1ef78c4a39, type: 3} + - _quadMesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Editor.meta b/Assets/Cinematic Effects/AmbientOcclusion/Editor.meta new file mode 100644 index 0000000..aedb738 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c1589efc0706e448d9a0af709e2c99cc +folderAsset: yes +timeCreated: 1457326964 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs new file mode 100644 index 0000000..82cae01 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs @@ -0,0 +1,63 @@ +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(AmbientOcclusion))] + public class AmbientOcclusionEditor : Editor + { + SerializedProperty _intensity; + SerializedProperty _radius; + SerializedProperty _sampleCount; + SerializedProperty _sampleCountValue; + SerializedProperty _downsampling; + SerializedProperty _ambientOnly; + SerializedProperty _debug; + + static GUIContent _textValue = new GUIContent("Value"); + + static string _textNoAmbientOnly = + "The ambient-only mode is currently disabled; " + + "it needs deferred shading and HDR rendering."; + + void OnEnable() + { + _intensity = serializedObject.FindProperty("settings.intensity"); + _radius = serializedObject.FindProperty("settings.radius"); + _sampleCount = serializedObject.FindProperty("settings.sampleCount"); + _sampleCountValue = serializedObject.FindProperty("settings.sampleCountValue"); + _downsampling = serializedObject.FindProperty("settings.downsampling"); + _ambientOnly = serializedObject.FindProperty("settings.ambientOnly"); + _debug = serializedObject.FindProperty("settings.debug"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(_intensity); + EditorGUILayout.PropertyField(_radius); + EditorGUILayout.PropertyField(_sampleCount); + + if (_sampleCount.hasMultipleDifferentValues || + _sampleCount.enumValueIndex == (int)AmbientOcclusion.SampleCount.Variable) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_sampleCountValue, _textValue); + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(_downsampling); + EditorGUILayout.PropertyField(_ambientOnly); + EditorGUILayout.PropertyField(_debug); + + // Show a warning if the ambient-only mode is not supported. + if (!_ambientOnly.hasMultipleDifferentValues && _ambientOnly.boolValue) + if (!((AmbientOcclusion)target).isAmbientOnlySupported) + EditorGUILayout.HelpBox(_textNoAmbientOnly, MessageType.Info); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta new file mode 100644 index 0000000..bb319ee --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05ea8e27ed8e74e67a9220b4f4119e51 +timeCreated: 1457327141 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta b/Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta new file mode 100644 index 0000000..127ad26 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1d775599023574a39befabe47bdfddde +folderAsset: yes +timeCreated: 1457326936 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs new file mode 100644 index 0000000..e53f0a4 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + // Observer class that detects changes on properties + struct PropertyObserver + { + // AO properties + bool _downsampling; + bool _ambientOnly; + + // Camera properties + int _pixelWidth; + int _pixelHeight; + + // Check if it has to reset itself for property changes. + public bool CheckNeedsReset(Settings setting, Camera camera) + { + return + _downsampling != setting.downsampling || + _ambientOnly != setting.ambientOnly || + _pixelWidth != camera.pixelWidth || + _pixelHeight != camera.pixelHeight; + } + + // Update the internal state. + public void Update(Settings setting, Camera camera) + { + _downsampling = setting.downsampling; + _ambientOnly = setting.ambientOnly; + _pixelWidth = camera.pixelWidth; + _pixelHeight = camera.pixelHeight; + } + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta new file mode 100644 index 0000000..2068429 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1d9548d9a173a40e4b758ecf6e4fed49 +timeCreated: 1457326885 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs new file mode 100644 index 0000000..5ce57f5 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs @@ -0,0 +1,71 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + /// Values for Settings.sampleCount, determining the number of sample points. + public enum SampleCount + { + Lowest, Low, Medium, High, Variable + } + + /// Class used for storing settings of AmbientOcclusion. + [Serializable] + public class Settings + { + /// Degree of darkness produced by the effect. + [SerializeField, Range(0, 4)] + [Tooltip("Degree of darkness produced by the effect.")] + public float intensity; + + /// Radius of sample points, which affects extent of darkened areas. + [SerializeField] + [Tooltip("Radius of sample points, which affects extent of darkened areas.")] + public float radius; + + /// Number of sample points, which affects quality and performance. + [SerializeField] + [Tooltip("Number of sample points, which affects quality and performance.")] + public SampleCount sampleCount; + + /// Determines the sample count when SampleCount.Variable is used. + [SerializeField] + [Tooltip("Determines the sample count when SampleCount.Variable is used.")] + public int sampleCountValue; + + /// Halves the resolution of the effect to increase performance. + [SerializeField] + [Tooltip("Halves the resolution of the effect to increase performance.")] + public bool downsampling; + + /// Enables the ambient-only mode in that the effect only affects + /// ambient lighting. This mode is only available with deferred + /// shading and HDR rendering. + [SerializeField] + [Tooltip("If checked, the effect only affects ambient lighting.")] + public bool ambientOnly; + + [SerializeField] + public bool debug; + + /// Returns the default settings. + public static Settings defaultSettings + { + get + { + return new Settings + { + intensity = 1, + radius = 0.3f, + sampleCount = SampleCount.Medium, + sampleCountValue = 24, + downsampling = false, + ambientOnly = false + }; + } + } + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta new file mode 100644 index 0000000..0a3a30a --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Helpers/Settings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e952a344c72354904a417d27abe6f55e +timeCreated: 1457331804 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Resources.meta b/Assets/Cinematic Effects/AmbientOcclusion/Resources.meta new file mode 100644 index 0000000..1719486 --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ae08100d29090452888e1b6a7b5a7170 +folderAsset: yes +timeCreated: 1457326958 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader new file mode 100644 index 0000000..f95f84c --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader @@ -0,0 +1,476 @@ +Shader "Hidden/Image Effects/Cinematic/AmbientOcclusion" +{ + Properties + { + _MainTex("", 2D) = ""{} + _OcclusionTexture("", 2D) = ""{} + } + CGINCLUDE + + // -------- + // Additional options for further customization + // -------- + + // By default, a fixed sampling pattern is used in the AO estimator. + // Although this gives preferable results in most cases, a completely + // random sampling pattern could give aesthetically good results in some + // cases. Comment out the line below to use the random pattern instead of + // the fixed one. + #define FIXED_SAMPLING_PATTERN 1 + + // The constant below determines the contrast of occlusion. Altough this + // allows intentional over/under occlusion, currently is not exposed to the + // editor, because it’s thought to be rarely useful. + static const float kContrast = 0.6; + + // The constant below controls the geometry-awareness of the blur filter. + // The higher value, the more sensitive it is. + static const float kGeom = 50; + + // The constants below are used in the AO estimator. Beta is mainly used + // for suppressing self-shadowing noise, and Epsilon is used to prevent + // calculation underflow. See the paper (Morgan 2011 http://goo.gl/2iz3P) + // for further details of these constants. + static const float kBeta = 0.002; + static const float kEpsilon = 1e-4; + + // -------- + + #include "UnityCG.cginc" + + #if _SAMPLECOUNT_LOWEST + static const int _SampleCount = 3; + #else + int _SampleCount; + #endif + + // Global shader properties + #if _SOURCE_GBUFFER + sampler2D _CameraGBufferTexture2; + sampler2D_float _CameraDepthTexture; + float4x4 _WorldToCamera; + #else + sampler2D_float _CameraDepthNormalsTexture; + #endif + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + sampler2D _OcclusionTexture; + + // Material shader properties + half _Intensity; + float _Radius; + float _TargetScale; + float2 _BlurVector; + + // Utility for sin/cos + float2 CosSin(float theta) + { + float sn, cs; + sincos(theta, sn, cs); + return float2(cs, sn); + } + + // Gamma encoding function for AO value + // (do nothing if in the linear mode) + half EncodeAO(half x) + { + // Gamma encoding + half x_g = 1 - pow(1 - x, 1 / 2.2); + // ColorSpaceLuminance.w is 0 (gamma) or 1 (linear). + return lerp(x_g, x, unity_ColorSpaceLuminance.w); + } + + // Pseudo random number generator with 2D argument + float UVRandom(float u, float v) + { + float f = dot(float2(12.9898, 78.233), float2(u, v)); + return frac(43758.5453 * sin(f)); + } + + // Interleaved gradient function from Jimenez 2014 http://goo.gl/eomGso + float GradientNoise(float2 uv) + { + uv = floor(uv * _ScreenParams.xy); + float f = dot(float2(0.06711056f, 0.00583715f), uv); + return frac(52.9829189f * frac(f)); + } + + // Boundary check for depth sampler + // (returns a very large value if it lies out of bounds) + float CheckBounds(float2 uv, float d) + { + float ob = any(uv < 0) + any(uv > 1); + #if defined(UNITY_REVERSED_Z) + ob += (d <= 0.00001); + #else + ob += (d >= 0.99999); + #endif + return ob * 1e8; + } + + // Depth/normal sampling functions + float SampleDepth(float2 uv) + { + #if _SOURCE_GBUFFER + float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); + return LinearEyeDepth(d) + CheckBounds(uv, d); + #else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + float d = DecodeFloatRG(cdn.zw); + return d * _ProjectionParams.z + CheckBounds(uv, d); + #endif + } + + float3 SampleNormal(float2 uv) + { + #if _SOURCE_GBUFFER + float3 norm = tex2D(_CameraGBufferTexture2, uv).xyz * 2 - 1; + return mul((float3x3)_WorldToCamera, norm); + #else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + return DecodeViewNormalStereo(cdn) * float3(1, 1, -1); + #endif + } + + float SampleDepthNormal(float2 uv, out float3 normal) + { + #if _SOURCE_GBUFFER + normal = SampleNormal(uv); + return SampleDepth(uv); + #else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + normal = DecodeViewNormalStereo(cdn) * float3(1, 1, -1); + float d = DecodeFloatRG(cdn.zw); + return d * _ProjectionParams.z + CheckBounds(uv, d); + #endif + } + + // Reconstruct view-space position from UV and depth. + // p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22) + // p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23) + float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31) + { + return float3((uv * 2 - 1 - p13_31) / p11_22, 1) * depth; + } + + // Normal vector comparer (for geometry-aware weighting) + half CompareNormal(half3 d1, half3 d2) + { + return pow((dot(d1, d2) + 1) * 0.5, kGeom); + } + + // Final combiner function + half3 CombineOcclusion(half3 src, half3 ao) + { + return lerp(src, 0, EncodeAO(ao)); + } + + // Sample point picker + float3 PickSamplePoint(float2 uv, float index) + { + // Uniformaly distributed points on a unit sphere http://goo.gl/X2F1Ho + #if FIXED_SAMPLING_PATTERN + float gn = GradientNoise(uv * _TargetScale); + float u = frac(UVRandom(0, index) + gn) * 2 - 1; + float theta = (UVRandom(1, index) + gn) * UNITY_PI * 2; + #else + float u = UVRandom(uv.x + _Time.x, uv.y + index) * 2 - 1; + float theta = UVRandom(-uv.x - _Time.x, uv.y + index) * UNITY_PI * 2; + #endif + float3 v = float3(CosSin(theta) * sqrt(1 - u * u), u); + // Make them distributed between [0, _Radius] + float l = sqrt((index + 1) / _SampleCount) * _Radius; + return v * l; + } + + // Occlusion estimator function + float EstimateOcclusion(float2 uv) + { + // Parameters used in coordinate conversion + float3x3 proj = (float3x3)unity_CameraProjection; + float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22); + float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23); + + // View space normal and depth + float3 norm_o; + float depth_o = SampleDepthNormal(uv, norm_o); + + #if _SOURCE_DEPTHNORMALS + // Offset the depth value to avoid precision error. + // (depth in the DepthNormals mode has only 16-bit precision) + depth_o -= _ProjectionParams.z / 65536; + #endif + + // Reconstruct the view-space position. + float3 vpos_o = ReconstructViewPos(uv, depth_o, p11_22, p13_31); + + // Distance-based AO estimator based on Morgan 2011 http://goo.gl/2iz3P + float ao = 0.0; + + for (int s = 0; s < _SampleCount; s++) + { + // Sample point + float3 v_s1 = PickSamplePoint(uv, s); + v_s1 = faceforward(v_s1, -norm_o, v_s1); + float3 vpos_s1 = vpos_o + v_s1; + + // Reproject the sample point + float3 spos_s1 = mul(proj, vpos_s1); + float2 uv_s1 = (spos_s1.xy / vpos_s1.z + 1) * 0.5; + + // Depth at the sample point + float depth_s1 = SampleDepth(uv_s1); + + // Relative position of the sample point + float3 vpos_s2 = ReconstructViewPos(uv_s1, depth_s1, p11_22, p13_31); + float3 v_s2 = vpos_s2 - vpos_o; + + // Estimate the obscurance value + float a1 = max(dot(v_s2, norm_o) - kBeta * depth_o, 0); + float a2 = dot(v_s2, v_s2) + kEpsilon; + ao += a1 / a2; + } + + ao *= _Radius; // intensity normalization + + // Apply other parameters. + return pow(ao * _Intensity / _SampleCount, kContrast); + } + + // Geometry-aware separable blur filter (large kernel) + half SeparableBlurLarge(sampler2D tex, float2 uv, float2 delta) + { + #if !SHADER_API_MOBILE + // 9-tap Gaussian blur with adaptive sampling + float2 uv1a = uv - delta; + float2 uv1b = uv + delta; + float2 uv2a = uv - delta * 2; + float2 uv2b = uv + delta * 2; + float2 uv3a = uv - delta * 3.2307692308; + float2 uv3b = uv + delta * 3.2307692308; + + half3 n0 = SampleNormal(uv); + + half w0 = 0.37004405286; + half w1a = CompareNormal(n0, SampleNormal(uv1a)) * 0.31718061674; + half w1b = CompareNormal(n0, SampleNormal(uv1b)) * 0.31718061674; + half w2a = CompareNormal(n0, SampleNormal(uv2a)) * 0.19823788546; + half w2b = CompareNormal(n0, SampleNormal(uv2b)) * 0.19823788546; + half w3a = CompareNormal(n0, SampleNormal(uv3a)) * 0.11453744493; + half w3b = CompareNormal(n0, SampleNormal(uv3b)) * 0.11453744493; + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1a).r * w1a; + s += tex2D(_MainTex, uv1b).r * w1b; + s += tex2D(_MainTex, uv2a).r * w2a; + s += tex2D(_MainTex, uv2b).r * w2b; + s += tex2D(_MainTex, uv3a).r * w3a; + s += tex2D(_MainTex, uv3b).r * w3b; + + return s / (w0 + w1a + w1b + w2a + w2b + w3a + w3b); + #else + // 9-tap Gaussian blur with linear sampling + // (less quality but slightly fast) + float2 uv1a = uv - delta * 1.3846153846; + float2 uv1b = uv + delta * 1.3846153846; + float2 uv2a = uv - delta * 3.2307692308; + float2 uv2b = uv + delta * 3.2307692308; + + half3 n0 = SampleNormal(uv); + + half w0 = 0.2270270270; + half w1a = CompareNormal(n0, SampleNormal(uv1a)) * 0.3162162162; + half w1b = CompareNormal(n0, SampleNormal(uv1b)) * 0.3162162162; + half w2a = CompareNormal(n0, SampleNormal(uv2a)) * 0.0702702703; + half w2b = CompareNormal(n0, SampleNormal(uv2b)) * 0.0702702703; + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1a).r * w1a; + s += tex2D(_MainTex, uv1b).r * w1b; + s += tex2D(_MainTex, uv2a).r * w2a; + s += tex2D(_MainTex, uv2b).r * w2b; + + return s / (w0 + w1a + w1b + w2a + w2b); + #endif + } + + // Geometry-aware separable blur filter (small kernel) + half SeparableBlurSmall(sampler2D tex, float2 uv, float2 delta) + { + float2 uv1 = uv - delta; + float2 uv2 = uv + delta; + + half3 n0 = SampleNormal(uv); + + half w0 = 2; + half w1 = CompareNormal(n0, SampleNormal(uv1)); + half w2 = CompareNormal(n0, SampleNormal(uv2)); + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1).r * w1; + s += tex2D(_MainTex, uv2).r * w2; + + return s / (w0 + w1 + w2); + } + + // Pass 0: Occlusion estimation + half4 frag_ao(v2f_img i) : SV_Target + { + return EstimateOcclusion(i.uv); + } + + // Pass 1: Primary blur filter + half4 frag_blur1(v2f_img i) : SV_Target + { + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurLarge(_MainTex, i.uv, delta); + } + + // Pass 2: Secondary blur filter + half4 frag_blur2(v2f_img i) : SV_Target + { + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurSmall(_MainTex, i.uv, delta); + } + + // Pass 3: Combiner for the forward mode + struct v2f_multitex + { + float4 pos : SV_POSITION; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + }; + + v2f_multitex vert_multitex(appdata_img v) + { + // Handles vertically-flipped case. + float vflip = sign(_MainTex_TexelSize.y); + + v2f_multitex o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv0 = v.texcoord.xy; + o.uv1 = (v.texcoord.xy - 0.5) * float2(1, vflip) + 0.5; + return o; + } + + half4 frag_combine(v2f_multitex i) : SV_Target + { + half4 src = tex2D(_MainTex, i.uv0); + half ao = tex2D(_OcclusionTexture, i.uv1).r; + return half4(CombineOcclusion(src.rgb, ao), src.a); + } + + // Pass 4: Combiner for the ambient-only mode + v2f_img vert_gbuffer(appdata_img v) + { + v2f_img o; + o.pos = v.vertex * float4(2, 2, 0, 0) + float4(0, 0, 0, 1); + #if UNITY_UV_STARTS_AT_TOP + o.uv = v.texcoord * float2(1, -1) + float2(0, 1); + #else + o.uv = v.texcoord; + #endif + return o; + } + +#if !SHADER_API_GLES // excluding the MRT pass under GLES2 + + struct CombinerOutput + { + half4 gbuffer0 : SV_Target0; + half4 gbuffer3 : SV_Target1; + }; + + CombinerOutput frag_gbuffer_combine(v2f_img i) + { + half ao = tex2D(_OcclusionTexture, i.uv).r; + CombinerOutput o; + o.gbuffer0 = half4(0, 0, 0, ao); + o.gbuffer3 = half4((half3)EncodeAO(ao), 0); + return o; + } + +#else + + fixed4 frag_gbuffer_combine(v2f_img i) : SV_Target0 + { + return 0; + } + +#endif + + // Pass 5: Debug blit + half4 frag_blit_ao(v2f_multitex i) : SV_Target + { + half4 src = tex2D(_MainTex, i.uv0); + half ao = tex2D(_OcclusionTexture, i.uv1).r; + return half4(CombineOcclusion(1, ao), src.a); + } + + ENDCG + + SubShader + { + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _SOURCE_DEPTHNORMALS _SOURCE_GBUFFER + #pragma multi_compile _ _SAMPLECOUNT_LOWEST + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _SOURCE_DEPTHNORMALS _SOURCE_GBUFFER + #pragma vertex vert_img + #pragma fragment frag_blur1 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _SOURCE_DEPTHNORMALS _SOURCE_GBUFFER + #pragma vertex vert_img + #pragma fragment frag_blur2 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_multitex + #pragma fragment frag_combine + #pragma target 3.0 + ENDCG + } + Pass + { + Blend Zero OneMinusSrcColor, Zero OneMinusSrcAlpha + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_gbuffer + #pragma fragment frag_gbuffer_combine + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_multitex + #pragma fragment frag_blit_ao + #pragma target 3.0 + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta new file mode 100644 index 0000000..b7de14f --- /dev/null +++ b/Assets/Cinematic Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 65e203e5acda447acbf9dc1ef78c4a39 +timeCreated: 1457327141 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom.meta b/Assets/Cinematic Effects/Bloom.meta new file mode 100644 index 0000000..7cd206d --- /dev/null +++ b/Assets/Cinematic Effects/Bloom.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 193f90bb87f484c62ad73788d9cb2d44 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Bloom.cs b/Assets/Cinematic Effects/Bloom/Bloom.cs new file mode 100644 index 0000000..fadd47f --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Bloom.cs @@ -0,0 +1,223 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Bloom")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class Bloom : MonoBehaviour + { + [Serializable] + public struct Settings + { + [SerializeField] + [Tooltip("Filters out pixels under this level of brightness.")] + public float threshold; + + public float thresholdGamma + { + set { threshold = value; } + get { return Mathf.Max(0.0f, threshold); } + } + + public float thresholdLinear + { + set { threshold = Mathf.LinearToGammaSpace(value); } + get { return Mathf.GammaToLinearSpace(thresholdGamma); } + } + + [SerializeField, Range(1, 7)] + [Tooltip("Changes extent of veiling effects in a screen resolution-independent fashion.")] + public float radius; + + [SerializeField] + [Tooltip("Blend factor of the result image.")] + public float intensity; + + [SerializeField] + [Tooltip("Controls filter quality and buffer resolution.")] + public bool highQuality; + + [SerializeField] + [Tooltip("Reduces flashing noise with an additional filter.")] + public bool antiFlicker; + + public static Settings defaultSettings + { + get + { + var settings = new Settings + { + threshold = 0.9f, + radius = 2.0f, + intensity = 0.7f, + highQuality = true, + antiFlicker = false + }; + return settings; + } + } + } + + #region Public Properties + + [SerializeField] + public Settings settings = Settings.defaultSettings; + + #endregion + + [SerializeField, HideInInspector] + private Shader m_Shader; + + public Shader shader + { + get + { + if (m_Shader == null) + { + const string shaderName = "Hidden/Image Effects/Cinematic/Bloom"; + m_Shader = Shader.Find(shaderName); + } + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + #region Private Members + + const int kMaxIterations = 16; + RenderTexture[] m_blurBuffer1 = new RenderTexture[kMaxIterations]; + RenderTexture[] m_blurBuffer2 = new RenderTexture[kMaxIterations]; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, true, false, this)) + enabled = false; + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + var useRGBM = Application.isMobilePlatform; + var isGamma = QualitySettings.activeColorSpace == ColorSpace.Gamma; + + // source texture size + var tw = source.width; + var th = source.height; + + // halve the texture size for the low quality mode + if (!settings.highQuality) + { + tw /= 2; + th /= 2; + } + + // blur buffer format + var rtFormat = useRGBM ? RenderTextureFormat.Default : RenderTextureFormat.DefaultHDR; + + // determine the iteration count + var logh = Mathf.Log(th, 2) + settings.radius - 8; + var logh_i = (int)logh; + var iterations = Mathf.Clamp(logh_i, 1, kMaxIterations); + + // update the shader properties + var threshold = settings.thresholdLinear; + material.SetFloat("_Threshold", threshold); + + const float softKneeRatio = 0.5f; + var knee = threshold * softKneeRatio + 1e-5f; + var curve = new Vector3(threshold - knee, knee * 2, 0.25f / knee); + material.SetVector("_Curve", curve); + + var pfo = !settings.highQuality && settings.antiFlicker; + material.SetFloat("_PrefilterOffs", pfo ? -0.5f : 0.0f); + + material.SetFloat("_SampleScale", 0.5f + logh - logh_i); + material.SetFloat("_Intensity", Mathf.Max(0.0f, settings.intensity)); + + if (settings.highQuality) + material.EnableKeyword("HIGH_QUALITY"); + else + material.DisableKeyword("HIGH_QUALITY"); + + if (settings.antiFlicker) + material.EnableKeyword("ANTI_FLICKER"); + else + material.DisableKeyword("ANTI_FLICKER"); + + if (isGamma) + { + material.DisableKeyword("LINEAR_COLOR"); + material.EnableKeyword("GAMMA_COLOR"); + } + else + { + material.EnableKeyword("LINEAR_COLOR"); + material.DisableKeyword("GAMMA_COLOR"); + } + + // prefilter pass + var prefiltered = RenderTexture.GetTemporary(tw, th, 0, rtFormat); + Graphics.Blit(source, prefiltered, material, 0); + + // construct a mip pyramid + var last = prefiltered; + for (var level = 0; level < iterations; level++) + { + m_blurBuffer1[level] = RenderTexture.GetTemporary(last.width / 2, last.height / 2, 0, rtFormat); + Graphics.Blit(last, m_blurBuffer1[level], material, (level == 0) ? 1 : 2); + last = m_blurBuffer1[level]; + } + + // upsample and combine loop + for (var level = iterations - 2; level >= 0; level--) + { + var basetex = m_blurBuffer1[level]; + material.SetTexture("_BaseTex", basetex); + m_blurBuffer2[level] = RenderTexture.GetTemporary(basetex.width, basetex.height, 0, rtFormat); + Graphics.Blit(last, m_blurBuffer2[level], material, 3); + last = m_blurBuffer2[level]; + } + + // finish process + material.SetTexture("_BaseTex", source); + Graphics.Blit(last, destination, material, 4); + + // release the temporary buffers + for (var i = 0; i < kMaxIterations; i++) + { + if (m_blurBuffer1[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer1[i]); + if (m_blurBuffer2[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer2[i]); + m_blurBuffer1[i] = null; + m_blurBuffer2[i] = null; + } + + RenderTexture.ReleaseTemporary(prefiltered); + } + + #endregion + } +} diff --git a/Assets/Cinematic Effects/Bloom/Bloom.cs.meta b/Assets/Cinematic Effects/Bloom/Bloom.cs.meta new file mode 100644 index 0000000..95024ea --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Bloom.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 32187365ced0c42219cde2b57c99b323 +timeCreated: 1454052338 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _shader: {fileID: 4800000, guid: e45d4f28262b04d10a075856ab5fdb5e, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Editor.meta b/Assets/Cinematic Effects/Bloom/Editor.meta new file mode 100644 index 0000000..0a74df6 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 92a024b1f1430409eb656f65969aa3d5 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs new file mode 100644 index 0000000..0a9e4f1 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(Bloom))] + public class BloomEditor : Editor + { + [NonSerialized] + private List m_Properties = new List(); + + void OnEnable() + { + var settings = FieldFinder.GetField(x => x.settings); + foreach (var setting in settings.FieldType.GetFields()) + { + var prop = settings.Name + "." + setting.Name; + m_Properties.Add(serializedObject.FindProperty(prop)); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta new file mode 100644 index 0000000..3569f9f --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Editor/BloomEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 38020a6029a85434a95a6f725a5aae5f +timeCreated: 1454052266 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Resources.meta b/Assets/Cinematic Effects/Bloom/Resources.meta new file mode 100644 index 0000000..7099ea8 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4af3202dbe79e460e9be42bcb6509fe0 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader new file mode 100644 index 0000000..9d23541 --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader @@ -0,0 +1,284 @@ +Shader "Hidden/Image Effects/Cinematic/Bloom" +{ + Properties + { + _MainTex("", 2D) = "" {} + _BaseTex("", 2D) = "" {} + } + + CGINCLUDE + + #include "UnityCG.cginc" + + // Mobile: use RGBM instead of float/half RGB + #define USE_RGBM defined(SHADER_API_MOBILE) + + sampler2D _MainTex; + sampler2D _BaseTex; + float2 _MainTex_TexelSize; + float2 _BaseTex_TexelSize; + + float _PrefilterOffs; + half _Threshold; + half3 _Curve; + float _SampleScale; + half _Intensity; + + // Brightness function + half Brightness(half3 c) + { + return max(max(c.r, c.g), c.b); + } + + // 3-tap median filter + half3 Median(half3 a, half3 b, half3 c) + { + return a + b + c - min(min(a, b), c) - max(max(a, b), c); + } + + // Clamp HDR value within a safe range + half3 SafeHDR(half3 c) { return min(c, 65000); } + half4 SafeHDR(half4 c) { return min(c, 65000); } + + // RGBM encoding/decoding + half4 EncodeHDR(float3 rgb) + { + #if USE_RGBM + rgb *= 1.0 / 8; + float m = max(max(rgb.r, rgb.g), max(rgb.b, 1e-6)); + m = ceil(m * 255) / 255; + return half4(rgb / m, m); + #else + return half4(rgb, 0); + #endif + } + + float3 DecodeHDR(half4 rgba) + { + #if USE_RGBM + return rgba.rgb * rgba.a * 8; + #else + return rgba.rgb; + #endif + } + + // Downsample with a 4x4 box filter + half3 DownsampleFilter(float2 uv) + { + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1); + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + return s * (1.0 / 4); + } + + // Downsample with a 4x4 box filter + anti-flicker filter + half3 DownsampleAntiFlickerFilter(float2 uv) + { + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1); + + half3 s1 = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + half3 s2 = DecodeHDR(tex2D(_MainTex, uv + d.zy)); + half3 s3 = DecodeHDR(tex2D(_MainTex, uv + d.xw)); + half3 s4 = DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + // Karis's luma weighted average + half s1w = 1 / (Brightness(s1) + 1); + half s2w = 1 / (Brightness(s2) + 1); + half s3w = 1 / (Brightness(s3) + 1); + half s4w = 1 / (Brightness(s4) + 1); + half one_div_wsum = 1.0 / (s1w + s2w + s3w + s4w); + + return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum; + } + + half3 UpsampleFilter(float2 uv) + { + #if HIGH_QUALITY + // 9-tap bilinear upsampler (tent filter) + float4 d = _MainTex_TexelSize.xyxy * float4(1, 1, -1, 0) * _SampleScale; + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv - d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv - d.wy)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv - d.zy)); + + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv )) * 4; + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)) * 2; + + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.wy)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv + d.xy)); + + return s * (1.0 / 16); + #else + // 4-tap bilinear upsampler + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1) * (_SampleScale * 0.5); + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + return s * (1.0 / 4); + #endif + } + + // + // Vertex shader + // + + struct v2f_multitex + { + float4 pos : SV_POSITION; + float2 uvMain : TEXCOORD0; + float2 uvBase : TEXCOORD1; + }; + + v2f_multitex vert_multitex(appdata_full v) + { + v2f_multitex o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uvMain = v.texcoord.xy; + o.uvBase = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if (_BaseTex_TexelSize.y < 0.0) + o.uvBase.y = 1.0 - v.texcoord.y; + #endif + return o; + } + + // + // fragment shader + // + + half4 frag_prefilter(v2f_img i) : SV_Target + { + float2 uv = i.uv + _MainTex_TexelSize.xy * _PrefilterOffs; + + #if ANTI_FLICKER + float3 d = _MainTex_TexelSize.xyx * float3(1, 1, 0); + half4 s0 = SafeHDR(tex2D(_MainTex, uv)); + half3 s1 = SafeHDR(tex2D(_MainTex, uv - d.xz).rgb); + half3 s2 = SafeHDR(tex2D(_MainTex, uv + d.xz).rgb); + half3 s3 = SafeHDR(tex2D(_MainTex, uv - d.zy).rgb); + half3 s4 = SafeHDR(tex2D(_MainTex, uv + d.zy).rgb); + half3 m = Median(Median(s0.rgb, s1, s2), s3, s4); + #else + half4 s0 = SafeHDR(tex2D(_MainTex, uv)); + half3 m = s0.rgb; + #endif + + #if GAMMA_COLOR + m = GammaToLinearSpace(m); + #endif + // Pixel brightness + half br = Brightness(m); + + // Under-threshold part: quadratic curve + half rq = clamp(br - _Curve.x, 0, _Curve.y); + rq = _Curve.z * rq * rq; + + // Combine and apply the brightness response curve. + m *= max(rq, br - _Threshold) / (br + 1e-5); + + return EncodeHDR(m); + } + + half4 frag_downsample1(v2f_img i) : SV_Target + { + #if ANTI_FLICKER + return EncodeHDR(DownsampleAntiFlickerFilter(i.uv)); + #else + return EncodeHDR(DownsampleFilter(i.uv)); + #endif + } + + half4 frag_downsample2(v2f_img i) : SV_Target + { + return EncodeHDR(DownsampleFilter(i.uv)); + } + + half4 frag_upsample(v2f_multitex i) : SV_Target + { + half3 base = DecodeHDR(tex2D(_BaseTex, i.uvBase)); + half3 blur = UpsampleFilter(i.uvMain); + return EncodeHDR(base + blur); + } + + half4 frag_upsample_final(v2f_multitex i) : SV_Target + { + half4 base = tex2D(_BaseTex, i.uvBase); + half3 blur = UpsampleFilter(i.uvMain); + #if GAMMA_COLOR + base.rgb = GammaToLinearSpace(base.rgb); + #endif + half3 cout = base.rgb + blur * _Intensity; + #if GAMMA_COLOR + cout = LinearToGammaSpace(cout); + #endif + return half4(cout, base.a); + } + + ENDCG + SubShader + { + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ ANTI_FLICKER + #pragma multi_compile LINEAR_COLOR GAMMA_COLOR + #pragma vertex vert_img + #pragma fragment frag_prefilter + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ ANTI_FLICKER + #pragma vertex vert_img + #pragma fragment frag_downsample1 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_downsample2 + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ HIGH_QUALITY + #pragma vertex vert_multitex + #pragma fragment frag_upsample + #pragma target 3.0 + ENDCG + } + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ HIGH_QUALITY + #pragma multi_compile LINEAR_COLOR GAMMA_COLOR + #pragma vertex vert_multitex + #pragma fragment frag_upsample_final + #pragma target 3.0 + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta new file mode 100644 index 0000000..c2a82ba --- /dev/null +++ b/Assets/Cinematic Effects/Bloom/Resources/Bloom.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e45d4f28262b04d10a075856ab5fdb5e +timeCreated: 1454052270 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta.meta b/Assets/Cinematic Effects/BloomBeta.meta new file mode 100644 index 0000000..4421927 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c6eb038cfff9e4dd990eeca4d9f4013f +folderAsset: yes +timeCreated: 1461974392 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Editor.meta b/Assets/Cinematic Effects/BloomBeta/Editor.meta new file mode 100644 index 0000000..ea5e5ab --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 59c160308a8e47545a7b1baa9377c744 +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs new file mode 100644 index 0000000..2510b00 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs @@ -0,0 +1,526 @@ +using UnityEngine; +using System.Collections.Generic; +using UnityEditor; +using System.IO; +using System; + +public class CameraDirtTextureGenerator : EditorWindow +{ + + + Texture2D m_DestinationTexture = null; + + [SerializeField] + int m_PassCount; + + + [SerializeField] + BokehGenerationPass[] m_BokehPasses = new BokehGenerationPass[5]; + + [Serializable] + class BokehGenerationPass + { + [SerializeField] + public Texture2D m_BokehTexture; + [SerializeField] + public float m_MinimumSize = 100.0f; + [SerializeField] + public float m_MaximumSize = 200.0f; + [SerializeField] + public float m_Density = 0.1f; + [SerializeField] + public float m_MinIntensity = 0.1f; + [SerializeField] + public float m_MaxIntensity = 0.3f; + [SerializeField] + public float m_BlurRadius = 1; + [SerializeField] + public float m_VignettePower = 0.5f; + [SerializeField] + public float m_ChromaticAberration = 20.0f; + [SerializeField] + public float m_HueVariation = 0.3f; + [SerializeField] + public bool m_RandomRotation = false; + } + + List[] m_Positions = new List[5]; + float[] m_MinimumDistance = new float[5]; + + Vector2 m_ScrollPos; + + [MenuItem("Window/Bokeh Texture Generator")] + public static void ShowWindow() + { + EditorWindow.GetWindow(typeof(CameraDirtTextureGenerator)); + } + + + GUIStyle m_Background1; + GUIStyle m_Background2; + GUIStyle m_Background3; + GUIStyle m_Background4; + void OnEnable() + { + m_Background1 = new GUIStyle(); + m_Background1.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.1f)); + m_Background2 = new GUIStyle(); + m_Background2.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.0f)); + m_Background3 = new GUIStyle(); + m_Background3.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.05f)); + m_Background4 = new GUIStyle(); + m_Background4.normal.background = MakeTex(600, 1, new Color(0.0f, 0.0f, 0.0f, 1.0f)); + + + } + + void OnDisable() + { + GameObject.DestroyImmediate(m_Background1.normal.background); + GameObject.DestroyImmediate(m_Background2.normal.background); + GameObject.DestroyImmediate(m_Background3.normal.background); + GameObject.DestroyImmediate(m_Background4.normal.background); + } + + void CreateAndSetTexture() + { + Texture2D tmp = new Texture2D(m_Width, m_Height); + var bytes = tmp.EncodeToPNG(); + File.WriteAllBytes("Assets/UB_BokehTexture.png", bytes); + AssetDatabase.ImportAsset("Assets/UB_BokehTexture.png"); + + m_DestinationTexture = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/UB_BokehTexture.png", typeof(Texture2D)); + } + + int m_Width = 1280; + int m_Height = 720; + + void OnGUI() + { + Undo.RecordObject(this, "Lens Bokeh Texture Generator"); + + GUILayout.Label("SETTINGS", EditorStyles.boldLabel); + + m_DestinationTexture = (Texture2D)EditorGUILayout.ObjectField("Destination Texture", m_DestinationTexture, typeof(Texture2D), false); + + if (m_DestinationTexture == null) + { + GUILayout.Label("Please set or create a destination texture."); + GUILayout.BeginHorizontal(); + m_Width = Mathf.Clamp(EditorGUILayout.IntField("Width", m_Width),10, 4096); + m_Height = Mathf.Clamp(EditorGUILayout.IntField("Height", m_Height), 10, 4096); + GUILayout.EndHorizontal(); + if (GUILayout.Button("Create and set Texture")) + { + CreateAndSetTexture(); + } + } + else + { + m_PassCount = Mathf.Clamp(EditorGUILayout.IntField("Layer Count", m_PassCount), 1, 5); + GUILayout.Space(20.0f); + GUILayout.Label("LAYERS", EditorStyles.boldLabel); + m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos); + for (int i = 0; i < m_PassCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + BokehGenerationPass p = m_BokehPasses[i]; + p.m_BokehTexture = (Texture2D)EditorGUILayout.ObjectField("Sprite Texture", p.m_BokehTexture, typeof(Texture2D), false); + p.m_MinimumSize = DoSlider("Minimum Size", p.m_MinimumSize, 20.0f, 400.0f); + p.m_MaximumSize = DoSlider("Maximum Size", p.m_MaximumSize, 20.0f, 400.0f); + p.m_BlurRadius = DoSlider("Blur Radius", p.m_BlurRadius, 0.0f, 10.0f); + p.m_VignettePower = DoSlider("Vignette Power", p.m_VignettePower, 0.0f, 10.0f); + p.m_HueVariation = DoSlider("Hue Variation", p.m_HueVariation, 0.0f, 0.8f); + p.m_MinIntensity = DoSlider("Minimum Intensity", p.m_MinIntensity, 0.0f, 1.0f); + p.m_MaxIntensity = DoSlider("Maximum Intensity", p.m_MaxIntensity, 0.0f, 1.0f); + p.m_Density = DoSlider("Density", p.m_Density, 0.0f, 1.0f); + p.m_ChromaticAberration = DoSlider("Chromatic Aberration", p.m_ChromaticAberration, 0.0f, 50.0f); + p.m_RandomRotation = EditorGUILayout.Toggle("Random Rotation", p.m_RandomRotation); + GUILayout.Space(20.0f); + GUILayout.EndVertical(); + } + GUILayout.EndScrollView(); + + + + + if (GUILayout.Button("Generate Bokeh Texture")) + { + GenerateTexture(); + } + + if (m_DestinationTexture != null) + { + GUILayout.BeginVertical(m_Background4); + + float w = m_DestinationTexture.width; + if (m_DestinationTexture.width > 300.0f) + w = 300.0f; + + float h = ((float)m_DestinationTexture.height / (float)m_DestinationTexture.width) * w; + + Rect r = GUILayoutUtility.GetRect(w, h); + + + r.position = new Vector2(r.width * 0.5f - w*0.5f, r.position.y); + + r.height = h; + r.width = w; + + //Debug.Log("r=" + h); + EditorGUI.DrawPreviewTexture(r, m_DestinationTexture); + + GUILayout.EndVertical(); + } + + + } + + + + if (GUI.changed) + { + EditorUtility.SetDirty(this); + } + } + + float DoSlider(string label, float value, float min, float max) + { + float v = value; + EditorGUILayout.BeginHorizontal(); + v = Mathf.Clamp(EditorGUILayout.FloatField(label, v), min, max); + v = GUILayout.HorizontalSlider(v, min, max); + EditorGUILayout.EndHorizontal(); + + return v; + } + + Material m_MixerMaterial = null; + + void GenerateTexture() + { + for (int i = 0; i < m_Positions.Length; ++i) + { + m_Positions[i] = new List(); + m_MinimumDistance[i] = 1.0f; + } + + Material bokehMaterial = new Material(Shader.Find("Hidden/Ultimate/BokehTexture")); + bokehMaterial.hideFlags = HideFlags.HideAndDontSave; + + Material blurMaterial = new Material(Shader.Find("Hidden/Ultimate/Sampling")); + blurMaterial.hideFlags = HideFlags.HideAndDontSave; + + Material miscMaterial = new Material(Shader.Find("Hidden/Ultimate/BokehMisc")); + miscMaterial.hideFlags = HideFlags.HideAndDontSave; + + Material mixerMaterial = new Material(Shader.Find("Hidden/Ultimate/BloomMixer")); + mixerMaterial.hideFlags = HideFlags.HideAndDontSave; + + m_MixerMaterial = mixerMaterial; + + RenderTexture accumulation = null; + for (int i = 0; i < m_PassCount; ++i) + { + RenderTexture current = GenerateTexture(i, bokehMaterial, blurMaterial, miscMaterial, m_DestinationTexture.width, m_DestinationTexture.height, m_BokehPasses[i]); + if (accumulation == null && current != null) + accumulation = current; + else if (current != null) + { + RenderTextureAdditive(current, accumulation, 1.0f); + RenderTexture.ReleaseTemporary(current); + } + } + + + string path = AssetDatabase.GetAssetPath(m_DestinationTexture); + + Texture2D newTexture = new Texture2D(m_DestinationTexture.width, m_DestinationTexture.height); + + RenderTexture.active = accumulation; + newTexture.ReadPixels(new Rect(0, 0, newTexture.width, newTexture.height), 0, 0); + newTexture.Apply(); + + var bytes = newTexture.EncodeToPNG(); + File.WriteAllBytes(path, bytes); + AssetDatabase.ImportAsset(path); + + GameObject.DestroyImmediate(bokehMaterial); + GameObject.DestroyImmediate(miscMaterial); + GameObject.DestroyImmediate(mixerMaterial); + + + } + + private RenderTexture GenerateTexture(int idx, Material material, Material blurMaterial, Material miscMaterial,int width, int height, BokehGenerationPass p) + { + RenderTexture rtA = RenderTexture.GetTemporary(width, height); + //RenderTexture lastActive = RenderTexture.active; + + material.mainTexture = p.m_BokehTexture; + + RenderTexture.active = rtA; + GL.Clear(true, true, Color.black); + + + //GL.LoadPixelMatrix(0,width,0,height); + //GL.LoadPixelMatrix(0, width, 0, height); + Matrix4x4 proj = Matrix4x4.Ortho(0, width, 0, height, -1.0f, 1.0f); + + material.SetMatrix("_MeshProjectionMatrix", proj); + + int nbPixel = width * height; + int nbQuad = (int)(p.m_Density * 0.0004f * nbPixel); + material.SetFloat("_Intensity", UnityEngine.Random.Range( p.m_MinIntensity, p.m_MaxIntensity) ); + + float cellSize = Mathf.Max( Mathf.Sqrt(nbQuad), 0.1f); + + float xStep = (float)width / cellSize; + float yStep = (float)height / cellSize; + + for (float i = 0; i < width; i += xStep) + { + for (float j = 0; j < height; j += yStep) + { + + Color tint = new Color(UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f)); + material.SetColor("_Tint", tint); + material.SetPass(0); + float size = UnityEngine.Random.Range(p.m_MinimumSize, p.m_MaximumSize); + + //float x = UnityEngine.Random.Range(-1f, 1f); + //float y = UnityEngine.Random.Range(-1f, 1f); + + + float x = (i + UnityEngine.Random.Range(0, xStep)) / width * 2.0f - 1.0f; + float y = (j + UnityEngine.Random.Range(0, yStep)) / height * 2.0f - 1.0f; + + float dist = new Vector2(x, y).magnitude; + float sizeMul = Mathf.Min(Mathf.Pow(dist, p.m_VignettePower), 1.0f); + + + float s = sizeMul > 0.5f ? size * sizeMul : 0.0f; + float angle = UnityEngine.Random.Range(0.0f, p.m_RandomRotation ? 360.0f : 0.0f); + Vector3 nDiv = new Vector3(1.0f / width, 1.0f / height, 0.0f); + Vector3 tl = RotateZ(new Vector3(-s, -s, 0.0f), angle); + Vector3 tr = RotateZ(new Vector3(s, -s, 0f), angle); + Vector3 br = RotateZ(new Vector3(s, s, 0f), angle); + Vector3 bl = RotateZ(new Vector3(-s, s, 0f), angle); + + tl = new Vector3(tl.x * nDiv.x, tl.y * nDiv.y, 0.0f); + tr = new Vector3(tr.x * nDiv.x, tr.y * nDiv.y, 0.0f); + br = new Vector3(br.x * nDiv.x, br.y * nDiv.y, 0.0f); + bl = new Vector3(bl.x * nDiv.x, bl.y * nDiv.y, 0.0f); + + + DrawQuad(x, y, tl, tr, br, bl); + + } + } + + if (material.SetPass(0)) + { + + /*for (int i = 0; i < nbQuad; ++i) + { + Color tint = new Color(UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f), UnityEngine.Random.Range(1.0f - p.m_HueVariation, 1.0f)); + material.SetColor("_Tint", tint); + material.SetPass(0); + float size = UnityEngine.Random.Range(p.m_MinimumSize, p.m_MaximumSize); + + //float x = UnityEngine.Random.Range(-1f, 1f); + //float y = UnityEngine.Random.Range(-1f, 1f); + + Vector3 pos = PickPosition(idx); + float x = pos.x; + float y = pos.y; + + float dist = new Vector2(x, y).magnitude; + float sizeMul = Mathf.Min(Mathf.Pow(dist, p.m_VignettePower), 1.0f); + + + float s = sizeMul > 0.5f ? size * sizeMul : 0.0f; + float angle = UnityEngine.Random.Range(0.0f, p.m_RandomRotation? 360.0f : 0.0f); + Vector3 nDiv = new Vector3(1.0f / width, 1.0f / height, 0.0f); + Vector3 tl = RotateZ(new Vector3(-s, -s, 0.0f), angle); + Vector3 tr = RotateZ(new Vector3(s, -s, 0f), angle); + Vector3 br = RotateZ(new Vector3(s, s, 0f), angle); + Vector3 bl = RotateZ(new Vector3(-s, s, 0f), angle); + + tl = new Vector3(tl.x * nDiv.x, tl.y * nDiv.y, 0.0f); + tr = new Vector3(tr.x * nDiv.x, tr.y * nDiv.y, 0.0f); + br = new Vector3(br.x * nDiv.x, br.y * nDiv.y, 0.0f); + bl = new Vector3(bl.x * nDiv.x, bl.y * nDiv.y, 0.0f); + + + DrawQuad(x, y, tl , tr , br , bl ); + }*/ + + } + + RenderTexture rtB = RenderTexture.GetTemporary(width, height); + for (int i = 0; i < 1; ++i) + { + RenderTexture.active = rtB; + blurMaterial.SetTexture("_AdditiveTexture", Texture2D.blackTexture); + blurMaterial.SetVector("_OffsetInfos", new Vector4(1.0f / width * p.m_BlurRadius, 0, 0, 0)); + blurMaterial.SetVector("_Tint", Color.white); + blurMaterial.SetFloat("_Intensity", 1.0f); + Graphics.Blit(rtA, rtB, blurMaterial, 2); + + blurMaterial.SetVector("_OffsetInfos", new Vector4(0, 1.0f / height * p.m_BlurRadius, 0, 0)); + Graphics.Blit(rtB, rtA, blurMaterial, 4); + } + + // Chromatic Aberration + miscMaterial.SetFloat("_ChromaticAberration", p.m_ChromaticAberration); + Graphics.Blit(rtA, rtB, miscMaterial, 0); + + /*RenderTexture.active = rtB; + Texture2D texture = new Texture2D(width, height); + texture.ReadPixels(new Rect(0, 0, width, height), 0, 0); + texture.Apply();*/ + + RenderTexture.ReleaseTemporary(rtA); + //RenderTexture.ReleaseTemporary(rtB); + //RenderTexture.active = lastActive; + + return rtB; + } + + Vector3 PickPosition(int idx) + { + float minDistance = m_MinimumDistance[idx]; + List positions = m_Positions[idx]; + + int nbTry = 20000; + bool ok = false; + + while (!ok) + { + float x = UnityEngine.Random.Range(-1f, 1f); + float y = UnityEngine.Random.Range(-1f, 1f); + + Vector3 pos = new Vector3(x, y, 0.0f); + + bool foundNearPos = false; + foreach (Vector3 cPos in positions) + { + if (Vector3.Distance(cPos, pos) < minDistance) + { + minDistance -= 0.1f; + m_MinimumDistance[idx] = minDistance; + foundNearPos = true; + break; + } + } + + if (!foundNearPos) + { + return pos; + } + + nbTry--; + if (nbTry < 0) + break; + } + + + + return Vector3.zero; + } + + public Vector3 RotateZ(Vector3 v, float angle) + { + float sin = Mathf.Sin(angle); + float cos = Mathf.Cos(angle); + + float tx = v.x; + float ty = v.y; + + Vector3 r = new Vector3(); + r.x = (cos * tx) - (sin * ty); + r.y = (cos * ty) + (sin * tx); + + return r; + } + + void DrawQuad(float x, float y, Vector3 tl, Vector3 tr, Vector3 br, Vector3 bl) + { + + + GL.Begin(GL.QUADS); // Quad + + GL.MultiTexCoord2(0, 1 - 0f, 0f); + GL.Vertex3(tl.x + x, tl.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 0f); + GL.Vertex3(tr.x + x, tr.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 1f); + GL.Vertex3(br.x + x, br.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 0f, 1f); + GL.Vertex3(bl.x + x, bl.y + y, 0f); + + GL.End(); + } + + /* void DrawQuad(float x, float y, float halfWidth, float halfHeight) + { + + float angle = UnityEngine.Random.Range(0.0f, 360.0f); + + + Vector3 tl = RotateZ(new Vector3(-halfWidth, -halfHeight, 0.0f), 0.0f); + Vector3 tr = RotateZ( new Vector3(halfWidth, -halfHeight, 0f), 0.0f); + Vector3 br = RotateZ(new Vector3(halfWidth, halfHeight, 0f), 0.0f); + Vector3 bl = RotateZ(new Vector3(-halfWidth, halfHeight, 0f), 0.0f); + + GL.Begin(GL.QUADS); // Quad + + GL.MultiTexCoord2(0, 1-0f, 0f); + GL.Vertex3(tl.x + x, tl.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 0f); + GL.Vertex3(tr.x + x, tr.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 1f, 1f); + GL.Vertex3(br.x + x, br.y + y, 0f); + + GL.MultiTexCoord2(0, 1 - 0f, 1f); + GL.Vertex3(bl.x + x, bl.y + y, 0f); + + GL.End(); + }*/ + + + private Texture2D MakeTex(int width, int height, Color col) + { + Color[] pix = new Color[width * height]; + + for (int i = 0; i < pix.Length; i++) + pix[i] = col; + + Texture2D result = new Texture2D(width, height); + result.hideFlags = HideFlags.HideAndDontSave; + result.SetPixels(pix); + result.Apply(); + + return result; + } + + void RenderTextureAdditive(RenderTexture source, RenderTexture destination, float intensity) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(source.width, source.height, source.depth, source.format); + Graphics.Blit(destination, tmpTexture); + + m_MixerMaterial.SetTexture("_ColorBuffer", tmpTexture); + m_MixerMaterial.SetFloat("_Intensity", intensity); + + Graphics.Blit(source, destination, m_MixerMaterial, 0); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta new file mode 100644 index 0000000..6b35c0b --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/BokehTextureGenerator.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a470493edcac30948be9a852dfd59a05 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs new file mode 100644 index 0000000..e0153ba --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs @@ -0,0 +1,445 @@ +using UnityEngine; +using System.Collections; +using UnityEditor; +using System.IO; + +[CustomEditor(typeof(UltimateBloom))] +public class UltimateBloomEditor : Editor +{ + + private Texture2D MakeTex(int width, int height, Color col) + { + Color[] pix = new Color[width * height]; + + for (int i = 0; i < pix.Length; i++) + pix[i] = col; + + Texture2D result = new Texture2D(width, height); + result.hideFlags = HideFlags.HideAndDontSave; + result.SetPixels(pix); + result.Apply(); + + return result; + } + + GUIStyle m_Background1; + GUIStyle m_Background2; + GUIStyle m_Background3; + + Texture2D m_Logo; + + public static string GetAbsoluteAssetPath(string path) + { + UltimateBloomPathLocator locator = ScriptableObject.CreateInstance(); + MonoScript script = MonoScript.FromScriptableObject(locator); + string scriptPath = AssetDatabase.GetAssetPath(script); + ScriptableObject.DestroyImmediate(locator); + return Path.GetDirectoryName(scriptPath) + "/" + path; + } + + void OnEnable() + { + m_Background1 = new GUIStyle(); + m_Background1.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.1f)); + m_Background2 = new GUIStyle(); + m_Background2.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.0f)); + m_Background3 = new GUIStyle(); + m_Background3.normal.background = MakeTex(600, 1, new Color(1.0f, 1.0f, 1.0f, 0.05f)); + + string logoPath = GetAbsoluteAssetPath("Editor/ub_logo.png"); + m_Logo = (Texture2D)AssetDatabase.LoadAssetAtPath(logoPath, typeof(Texture2D)); + + if (m_Logo != null) + m_Logo.hideFlags = HideFlags.HideAndDontSave; + } + + void OnDisable() + { + GameObject.DestroyImmediate(m_Background1.normal.background); + GameObject.DestroyImmediate(m_Background2.normal.background); + GameObject.DestroyImmediate(m_Background3.normal.background); + } + + + public override void OnInspectorGUI() + { + UltimateBloom bloomDeluxe = (UltimateBloom)target; + Undo.RecordObject(bloomDeluxe, "Bloom DELUXE"); + + if (m_Logo != null) + { + Rect rect = GUILayoutUtility.GetRect(m_Logo.width, m_Logo.height); + GUI.DrawTexture(rect, m_Logo, ScaleMode.ScaleToFit); + } + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowBloomSettings = UBHelper.GroupHeader("Bloom Settings", bloomDeluxe.m_UiShowBloomSettings); + if (bloomDeluxe.m_UiShowBloomSettings) + { + + bloomDeluxe.m_HDR = (UltimateBloom.HDRBloomMode)EditorGUILayout.EnumPopup("HDR", bloomDeluxe.m_HDR); + bloomDeluxe.m_InvertImage = EditorGUILayout.Toggle("Flip Image", bloomDeluxe.m_InvertImage); + + + bloomDeluxe.m_BloomIntensity = DoSlider("Bloom Master Intensity", bloomDeluxe.m_BloomIntensity, 0.0f, 5.0f); + //bloomDeluxe.m_BloomIntensity = Mathf.Clamp(EditorGUILayout.FloatField("Bloom Master Intensity", bloomDeluxe.m_BloomIntensity), 0.0f, 100.0f); + bloomDeluxe.m_DownscaleCount = Mathf.Clamp(EditorGUILayout.IntField("Layers (Downscale Count)", bloomDeluxe.m_DownscaleCount), 1, 6); + if (GUILayout.Button((bloomDeluxe.m_UiShowBloomScales ? "Hide Layers" : "Show Layers") + "[" + bloomDeluxe.m_DownscaleCount + "]")) + bloomDeluxe.m_UiShowBloomScales = !bloomDeluxe.m_UiShowBloomScales; + + if (bloomDeluxe.m_UiShowBloomScales) + { + + for (int i = 0; i < bloomDeluxe.m_DownscaleCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + int idx = i + 1; + bloomDeluxe.m_BloomUsages[i] = EditorGUILayout.Toggle(" Layer " + idx + " Enabled", bloomDeluxe.m_BloomUsages[i]); + bloomDeluxe.m_BloomIntensities[i] = DoSlider(" Layer " + idx + " Intensity", bloomDeluxe.m_BloomIntensities[i], 0.0f, 5.0f); + bloomDeluxe.m_BloomColors[i] = EditorGUILayout.ColorField(" Layer " + idx + " Tint", bloomDeluxe.m_BloomColors[i]); + GUILayout.EndVertical(); + } + } + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Intensity Management + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowIntensity = UBHelper.GroupHeader("Intensity Settings", bloomDeluxe.m_UiShowIntensity); + if (bloomDeluxe.m_UiShowIntensity) + { + UltimateBloom.BloomIntensityManagement lastIm = bloomDeluxe.m_IntensityManagement; + bloomDeluxe.m_IntensityManagement = (UltimateBloom.BloomIntensityManagement)EditorGUILayout.EnumPopup("Intensity Function", bloomDeluxe.m_IntensityManagement); + if (bloomDeluxe.m_IntensityManagement == UltimateBloom.BloomIntensityManagement.Threshold) + { + bloomDeluxe.m_BloomThreshhold = DoSlider(" Threshold", bloomDeluxe.m_BloomThreshhold, 0.0f, 5.0f); + } + else if (bloomDeluxe.m_IntensityManagement == UltimateBloom.BloomIntensityManagement.FilmicCurve) + { + bloomDeluxe.m_BloomCurve.OnGUI(); + } + if (lastIm != bloomDeluxe.m_IntensityManagement) + bloomDeluxe.ForceShadersReload(); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Sampling + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowSampling = UBHelper.GroupHeader("Sampling", bloomDeluxe.m_UiShowSampling); + if (bloomDeluxe.m_UiShowSampling) + { + bloomDeluxe.m_TemporalStableDownsampling = EditorGUILayout.Toggle("Temporal Stability Filter", bloomDeluxe.m_TemporalStableDownsampling); + bloomDeluxe.m_SamplingMode = (UltimateBloom.SamplingMode)EditorGUILayout.EnumPopup("Sampling Mode", bloomDeluxe.m_SamplingMode); + if (bloomDeluxe.m_SamplingMode == UltimateBloom.SamplingMode.Fixed) + bloomDeluxe.m_UpsamplingQuality = (UltimateBloom.BloomSamplingQuality)EditorGUILayout.EnumPopup("Sampling Kernel Size", bloomDeluxe.m_UpsamplingQuality); + else // Screen relative sampling + { + bloomDeluxe.m_SamplingMinHeight = DoSlider("Min Height", bloomDeluxe.m_SamplingMinHeight, 300.0f, 1000.0f); + + if (GUILayout.Button((bloomDeluxe.m_UiShowHeightSampling ? "Hide Sampling Heights" : "Show Sampling Heights"))) + bloomDeluxe.m_UiShowHeightSampling = !bloomDeluxe.m_UiShowHeightSampling; + + if (bloomDeluxe.m_UiShowHeightSampling) + { + bloomDeluxe.ComputeResolutionRelativeData(); + for (int i = 0; i < bloomDeluxe.m_ResSamplingPixelCount.Length; ++i) + { + GUILayout.Label("Sampling Height[" + i + "] = " + bloomDeluxe.m_ResSamplingPixelCount[i]); + } + } + } + + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Optimizations + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowOptimizations = UBHelper.GroupHeader("Optimizations", bloomDeluxe.m_UiShowOptimizations); + if (bloomDeluxe.m_UiShowOptimizations) + { + bloomDeluxe.m_DirectDownSample = EditorGUILayout.Toggle("Direct Downsampling", bloomDeluxe.m_DirectDownSample); + if (bloomDeluxe.m_DirectDownSample) + EditorGUILayout.HelpBox("Enabling direct downsampling may introduce jittering. It should only be enabled on low end hardwares.", MessageType.Info); + bloomDeluxe.m_DirectUpsample = EditorGUILayout.Toggle("Direct Upsampling", bloomDeluxe.m_DirectUpsample); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // LENS DUST + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowLensDirt = UBHelper.GroupHeader("Lens Dirt", bloomDeluxe.m_UiShowLensDirt); + if (bloomDeluxe.m_UiShowLensDirt) + { + bool lastUseLensDust = bloomDeluxe.m_UseLensDust; + bloomDeluxe.m_UseLensDust = EditorGUILayout.Toggle("Use Lens Dirt", bloomDeluxe.m_UseLensDust); + if (bloomDeluxe.m_UseLensDust) + { + bloomDeluxe.m_DustTexture = (Texture2D)EditorGUILayout.ObjectField(" Dirt Texture", bloomDeluxe.m_DustTexture, typeof(Texture2D), false); + bloomDeluxe.m_DustIntensity = DoSlider(" Dirtiness", bloomDeluxe.m_DustIntensity, 0.0f, 10.0f); + bloomDeluxe.m_DirtLightIntensity = DoSlider(" Dirt Light Intensity", bloomDeluxe.m_DirtLightIntensity, 0.0f, 30.0f); + } + if (lastUseLensDust != bloomDeluxe.m_UseLensDust) + bloomDeluxe.ForceShadersReload(); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // LENS FLARE + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowLensFlare = UBHelper.GroupHeader("Lens Flare (Bokeh & Ghost)", bloomDeluxe.m_UiShowLensFlare); + if (bloomDeluxe.m_UiShowLensFlare) + { + bool lastUseLensFlare = bloomDeluxe.m_UseLensFlare; + bloomDeluxe.m_UseLensFlare = EditorGUILayout.Toggle("Use Lens Flare", bloomDeluxe.m_UseLensFlare); + if (bloomDeluxe.m_UseLensFlare) + { + UltimateBloom.FlarePresets preset = (UltimateBloom.FlarePresets)EditorGUILayout.EnumPopup("Flare Preset", UltimateBloom.FlarePresets.ChoosePreset); + SetFlarePreset(preset, bloomDeluxe); + + bloomDeluxe.m_FlareRendering = (UltimateBloom.FlareRendering)EditorGUILayout.EnumPopup(" Flare Rendering", bloomDeluxe.m_FlareRendering); + if (bloomDeluxe.m_FlareRendering != UltimateBloom.FlareRendering.Sharp) + { + bloomDeluxe.m_FlareBlurQuality = (UltimateBloom.FlareBlurQuality)EditorGUILayout.EnumPopup(" Blur Quality", bloomDeluxe.m_FlareBlurQuality); + } + + UltimateBloom.FlareType lastFareType = bloomDeluxe.m_FlareType; + bloomDeluxe.m_FlareType = (UltimateBloom.FlareType)EditorGUILayout.EnumPopup(" Flare Duplication", bloomDeluxe.m_FlareType); + if (lastFareType != bloomDeluxe.m_FlareType) + bloomDeluxe.ForceShadersReload(); + + bloomDeluxe.m_FlareIntensity = DoSlider(" Flare Intensity", bloomDeluxe.m_FlareIntensity, 0.0f, 30.0f); + bloomDeluxe.m_FlareTreshold = DoSlider(" Threshold", bloomDeluxe.m_FlareTreshold, 0.0f, 5.0f); + bloomDeluxe.m_FlareGlobalScale = DoSlider(" Global Scale", bloomDeluxe.m_FlareGlobalScale, 0.1f, 5.0f); + bloomDeluxe.m_FlareScales = EditorGUILayout.Vector4Field(" Flare Scales Far", bloomDeluxe.m_FlareScales); + if (bloomDeluxe.m_FlareType == UltimateBloom.FlareType.Double) + bloomDeluxe.m_FlareScalesNear = EditorGUILayout.Vector4Field(" Flare Scales Near", bloomDeluxe.m_FlareScalesNear); + Vector4 tmp = bloomDeluxe.m_FlareScales; + float maxFlareScale = 12.0f; + bloomDeluxe.m_FlareScales = new Vector4(Mathf.Clamp(tmp.x, 0, maxFlareScale), Mathf.Clamp(tmp.y, 0, maxFlareScale), Mathf.Clamp(tmp.z, 0, maxFlareScale), Mathf.Clamp(tmp.w, 0, maxFlareScale)); + + tmp = bloomDeluxe.m_FlareScalesNear; + bloomDeluxe.m_FlareScalesNear = new Vector4(Mathf.Clamp(tmp.x, 0, maxFlareScale), Mathf.Clamp(tmp.y, 0, maxFlareScale), Mathf.Clamp(tmp.z, 0, maxFlareScale), Mathf.Clamp(tmp.w, 0, maxFlareScale)); + + bloomDeluxe.m_FlareTint0 = EditorGUILayout.ColorField(" Flare Tint 0", bloomDeluxe.m_FlareTint0); + bloomDeluxe.m_FlareTint1 = EditorGUILayout.ColorField(" Flare Tint 1", bloomDeluxe.m_FlareTint1); + bloomDeluxe.m_FlareTint2 = EditorGUILayout.ColorField(" Flare Tint 2", bloomDeluxe.m_FlareTint2); + bloomDeluxe.m_FlareTint3 = EditorGUILayout.ColorField(" Flare Tint 3", bloomDeluxe.m_FlareTint3); + + if (bloomDeluxe.m_FlareType == UltimateBloom.FlareType.Double) + { + bloomDeluxe.m_FlareTint4 = EditorGUILayout.ColorField(" Flare Tint 4", bloomDeluxe.m_FlareTint4); + bloomDeluxe.m_FlareTint5 = EditorGUILayout.ColorField(" Flare Tint 5", bloomDeluxe.m_FlareTint5); + bloomDeluxe.m_FlareTint6 = EditorGUILayout.ColorField(" Flare Tint 6", bloomDeluxe.m_FlareTint6); + bloomDeluxe.m_FlareTint7 = EditorGUILayout.ColorField(" Flare Tint 7", bloomDeluxe.m_FlareTint7); + } + + bloomDeluxe.m_FlareMask = (Texture2D)EditorGUILayout.ObjectField(" Flare Mask", bloomDeluxe.m_FlareMask, typeof(Texture2D), false); + + bloomDeluxe.m_UseBokehFlare = EditorGUILayout.Toggle("Use Bokeh Texture", bloomDeluxe.m_UseBokehFlare); + if (bloomDeluxe.m_UseBokehFlare) + { + bloomDeluxe.m_BokehFlareQuality = (UltimateBloom.BokehFlareQuality)EditorGUILayout.EnumPopup(" Bokeh Quality", bloomDeluxe.m_BokehFlareQuality); + + bloomDeluxe.m_BokehScale = Mathf.Clamp(EditorGUILayout.FloatField(" Bokeh Scale", bloomDeluxe.m_BokehScale), 0.2f, 2.5f); + bloomDeluxe.m_FlareShape = (Texture2D)EditorGUILayout.ObjectField(" Bokeh Texture", bloomDeluxe.m_FlareShape, typeof(Texture2D), false); + } + } + if (lastUseLensFlare != bloomDeluxe.m_UseLensFlare) + bloomDeluxe.ForceShadersReload(); + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Anamorphic lens flare + + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowAnamorphic = UBHelper.GroupHeader("Anamorphic Lens Flare", bloomDeluxe.m_UiShowAnamorphic); + if (bloomDeluxe.m_UiShowAnamorphic) + { + bool lastUseAnamorphic = bloomDeluxe.m_UseAnamorphicFlare; + bloomDeluxe.m_UseAnamorphicFlare = EditorGUILayout.Toggle("Use Anamorphic Lens Flare", bloomDeluxe.m_UseAnamorphicFlare); + if (bloomDeluxe.m_UseAnamorphicFlare) + { + bloomDeluxe.m_AnamorphicDownscaleCount = Mathf.Clamp(EditorGUILayout.IntField(" Layers (Downscale Count)", bloomDeluxe.m_AnamorphicDownscaleCount), 1, 6); + bloomDeluxe.m_AnamorphicFlareIntensity = DoSlider(" Intensity", bloomDeluxe.m_AnamorphicFlareIntensity, 0.0f, 5.0f); + //bloomDeluxe.m_AnamorphicFlareTreshold = DoSlider(" Treshold", bloomDeluxe.m_AnamorphicFlareTreshold, 0.0f, 5.0f); + bloomDeluxe.m_AnamorphicScale = DoSlider(" Scale", bloomDeluxe.m_AnamorphicScale, 0.0f, 6.0f); + bloomDeluxe.m_AnamorphicBlurPass = Mathf.Clamp(EditorGUILayout.IntField(" Blur Pass", bloomDeluxe.m_AnamorphicBlurPass), 1, 6); + bloomDeluxe.m_AnamorphicSmallVerticalBlur = EditorGUILayout.Toggle(" Anti-jitter Pass", bloomDeluxe.m_AnamorphicSmallVerticalBlur); + bloomDeluxe.m_AnamorphicDirection = (UltimateBloom.AnamorphicDirection)EditorGUILayout.EnumPopup(" Direction", bloomDeluxe.m_AnamorphicDirection); + } + if (lastUseAnamorphic != bloomDeluxe.m_UseAnamorphicFlare) + bloomDeluxe.ForceShadersReload(); + + if (bloomDeluxe.m_UseAnamorphicFlare) + { + if (GUILayout.Button((bloomDeluxe.m_UiShowAnamorphicBloomScales ? "Hide Layers" : "Show Layers") + "[" + bloomDeluxe.m_AnamorphicDownscaleCount + "]")) + bloomDeluxe.m_UiShowAnamorphicBloomScales = !bloomDeluxe.m_UiShowAnamorphicBloomScales; + if (bloomDeluxe.m_UiShowAnamorphicBloomScales) + { + for (int i = 0; i < bloomDeluxe.m_AnamorphicDownscaleCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + int idx = i + 1; + bloomDeluxe.m_AnamorphicBloomUsages[i] = EditorGUILayout.Toggle(" Layer " + idx + " Enabled", bloomDeluxe.m_AnamorphicBloomUsages[i]); + bloomDeluxe.m_AnamorphicBloomIntensities[i] = DoSlider(" Layer " + idx + " Intensity", bloomDeluxe.m_AnamorphicBloomIntensities[i], 0.0f, 5.0f); + bloomDeluxe.m_AnamorphicBloomColors[i] = EditorGUILayout.ColorField(" Layer " + idx + " Tint", bloomDeluxe.m_AnamorphicBloomColors[i]); + GUILayout.EndVertical(); + } + } + } + + GUILayout.Space(10.0f); + } + GUILayout.EndVertical(); + + // Star lens flare + + GUILayout.BeginVertical("Box"); + bloomDeluxe.m_UiShowStar = UBHelper.GroupHeader("Star Lens Flare", bloomDeluxe.m_UiShowStar); + if (bloomDeluxe.m_UiShowStar) + { + bool lastUseStar = bloomDeluxe.m_UseStarFlare; + bloomDeluxe.m_UseStarFlare = EditorGUILayout.Toggle("Use Star Lens Flare", bloomDeluxe.m_UseStarFlare); + if (bloomDeluxe.m_UseStarFlare) + { + bloomDeluxe.m_StarDownscaleCount = Mathf.Clamp(EditorGUILayout.IntField(" Layers (Downscale Count)", bloomDeluxe.m_StarDownscaleCount), 1, 6); + bloomDeluxe.m_StarFlareIntensity = DoSlider(" Intensity", bloomDeluxe.m_StarFlareIntensity, 0.0f, 5.0f); + //bloomDeluxe.m_StarFlareTreshol = DoSlider(" Treshold", bloomDeluxe.m_StarFlareTreshol, 0.0f, 5.0f); + bloomDeluxe.m_StarScale = DoSlider(" Scale", bloomDeluxe.m_StarScale, 0.0f, 5.0f); + bloomDeluxe.m_StarBlurPass = Mathf.Clamp(EditorGUILayout.IntField(" Blur Pass", bloomDeluxe.m_StarBlurPass), 1, 4); + } + if (lastUseStar != bloomDeluxe.m_UseStarFlare) + bloomDeluxe.ForceShadersReload(); + + if (bloomDeluxe.m_UseStarFlare) + { + if (GUILayout.Button((bloomDeluxe.m_UiShowStarBloomScales ? "Hide Layers" : "Show Layers") + "[" + bloomDeluxe.m_StarDownscaleCount + "]")) + bloomDeluxe.m_UiShowStarBloomScales = !bloomDeluxe.m_UiShowStarBloomScales; + if (bloomDeluxe.m_UiShowStarBloomScales) + { + for (int i = 0; i < bloomDeluxe.m_StarDownscaleCount; ++i) + { + GUILayout.BeginVertical(i % 2 == 0 ? m_Background3 : m_Background1); + int idx = i + 1; + bloomDeluxe.m_StarBloomUsages[i] = EditorGUILayout.Toggle(" Layer " + idx + " Enabled", bloomDeluxe.m_StarBloomUsages[i]); + bloomDeluxe.m_StarBloomIntensities[i] = DoSlider(" Layer " + idx + " Intensity", bloomDeluxe.m_StarBloomIntensities[i], 0.0f, 5.0f); + bloomDeluxe.m_StarBloomColors[i] = EditorGUILayout.ColorField(" Layer " + idx + " Tint", bloomDeluxe.m_StarBloomColors[i]); + GUILayout.EndVertical(); + } + } + } + } + GUILayout.EndVertical(); + + if (GUI.changed) + { + EditorUtility.SetDirty(target); + } + } + + + [MenuItem("Component/UltimateBloom/Add to selected camera")] + public static void AddPreset() + { + UltimateBloom ub = GetUltimateBloomObject(); + if (ub == null) + return; + + + } + + private static UltimateBloom GetUltimateBloomObject() + { + GameObject obj = Selection.activeGameObject; + if (obj == null) + return null; + if (obj.GetComponent() == null) + return null; + + return obj.AddComponent(); + } + + float DoSlider(string label, float value, float min, float max) + { + float v = value; + EditorGUILayout.BeginHorizontal(); + v = Mathf.Clamp(EditorGUILayout.FloatField(label, v, GUILayout.ExpandWidth(false)), min, max); + v = GUILayout.HorizontalSlider(v, min, max); + EditorGUILayout.EndHorizontal(); + + return v; + } + + void SetFlarePreset(UltimateBloom.FlarePresets preset, UltimateBloom ub) + { + if (preset == UltimateBloom.FlarePresets.ChoosePreset) + return; + + if (preset == UltimateBloom.FlarePresets.Bokeh2 || preset == UltimateBloom.FlarePresets.Ghost2) + { + ub.m_FlareTint0 = new Color(78 / 255.0f, 69 / 255.0f, 149.0f / 255.0f); + ub.m_FlareTint1 = new Color(36 / 255.0f, 51 / 255.0f, 141 / 255.0f); + ub.m_FlareTint2 = new Color(29 / 255.0f, 41 / 255.0f, 105 / 255.0f); + ub.m_FlareTint3 = new Color(17 / 255.0f, 22 / 255.0f, 107 / 255.0f); + ub.m_FlareTint4 = new Color(78 / 255.0f, 69 / 255.0f, 149.0f / 255.0f); + ub.m_FlareTint5 = new Color(36 / 255.0f, 51 / 255.0f, 141 / 255.0f); + ub.m_FlareTint6 = new Color(29 / 255.0f, 41 / 255.0f, 105 / 255.0f); + ub.m_FlareTint7 = new Color(17 / 255.0f, 22 / 255.0f, 107 / 255.0f); + } + else if (preset == UltimateBloom.FlarePresets.Bokeh3 || preset == UltimateBloom.FlarePresets.Ghost3) + { + ub.m_FlareTint0 = new Color(255 / 255.0f, 135 / 255.0f, 2/ 255.0f); + ub.m_FlareTint1 = new Color(255 / 255.0f, 96 / 255.0f, 1 / 255.0f); + ub.m_FlareTint2 = new Color(255 / 255.0f, 60 / 255.0f, 1 / 255.0f); + ub.m_FlareTint3 = new Color(255 / 255.0f, 12 / 255.0f, 0 / 255.0f); + ub.m_FlareTint4 = new Color(255 / 255.0f, 184 / 255.0f, 3 / 255.0f); + ub.m_FlareTint5 = new Color(255 / 255.0f, 135 / 255.0f, 2 / 255.0f); + ub.m_FlareTint6 = new Color(255 / 255.0f, 135 / 255.0f, 2 / 255.0f); + ub.m_FlareTint7 = new Color(255 / 255.0f, 96 / 255.0f, 0 / 255.0f); + } + else + { + ub.m_FlareTint0 = new Color(137 / 255.0f, 82 / 255.0f, 0 / 255.0f); + ub.m_FlareTint1 = new Color(0 / 255.0f, 63 / 255.0f, 126 / 255.0f); + ub.m_FlareTint2 = new Color(72 / 255.0f, 151 / 255.0f, 0 / 255.0f); + ub.m_FlareTint3 = new Color(114 / 255.0f, 35 / 255.0f, 0 / 255.0f); + ub.m_FlareTint4 = new Color(122 / 255.0f, 88 / 255.0f, 0 / 255.0f); + ub.m_FlareTint5 = new Color(137 / 255.0f, 71 / 255.0f, 0 / 255.0f); + ub.m_FlareTint6 = new Color(97 / 255.0f, 139 / 255.0f, 0 / 255.0f); + ub.m_FlareTint7 = new Color(40 / 255.0f, 142 / 255.0f, 0 / 255.0f); + } + + ub.m_FlareIntensity = 1.0f; + ub.m_FlareTreshold = 0.8f; + + if (preset == UltimateBloom.FlarePresets.Bokeh1 || preset == UltimateBloom.FlarePresets.Bokeh2 || preset == UltimateBloom.FlarePresets.Bokeh3) + { + ub.m_FlareScales = new Vector4(5.77f, 2.5f, 1.32f, 1.12f); + ub.m_FlareScalesNear = new Vector4(12, 7.37f, 5.3f, 4.14f); + ub.m_FlareRendering = UltimateBloom.FlareRendering.Sharp; + ub.m_UseBokehFlare = true; + + } + else + { + ub.m_FlareScales = new Vector4(1.0f, 0.6f, 0.5f, 0.4f); + ub.m_FlareScalesNear = new Vector4(1.0f, 0.8f, 0.6f, 0.5f); + ub.m_FlareBlurQuality = UltimateBloom.FlareBlurQuality.High; + ub.m_FlareRendering = UltimateBloom.FlareRendering.Blurred; + ub.m_UseBokehFlare = false; + + + if (preset == UltimateBloom.FlarePresets.GhostFast) + ub.m_FlareBlurQuality = UltimateBloom.FlareBlurQuality.Fast; + } + + } + + void ChangeQualityPreset(UltimateBloom.BloomQualityPreset newPreset) + { + + } +} diff --git a/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta new file mode 100644 index 0000000..f7aca00 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Editor/UltimateBloomEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 285efee97a9b0b742b510e3de78b0b38 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics.meta b/Assets/Cinematic Effects/BloomBeta/Graphics.meta new file mode 100644 index 0000000..e0a7ec7 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7ffc125439b8b7b40bca3705f9e0a6eb +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png new file mode 100644 index 0000000..31f7f52 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta new file mode 100644 index 0000000..0eae706 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokeh.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: c689cb7ab25ee59439a73274bbcda927 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png new file mode 100644 index 0000000..8baa4ff Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta new file mode 100644 index 0000000..c5d6603 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/BokehRound.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: d27d217d25bb6e44ca371090b6169245 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png new file mode 100644 index 0000000..da03c38 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta new file mode 100644 index 0000000..7364fc5 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/Bokehround2.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 58c6d4ee6f7515d428df6d3f41dd1c26 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png new file mode 100644 index 0000000..3048937 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png.meta new file mode 100644 index 0000000..2671776 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMask.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 9caff1227d841d143862adba1dc06356 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat new file mode 100644 index 0000000..3914c0d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: FlareMaterial + m_Shader: {fileID: 4800000, guid: abe4898237b1d4d49b8a3ebc0f5b4d49, type: 3} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: 14a3e99f4d475b64990c89f22f1e307a, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BrightTexture + second: + m_Texture: {fileID: 2800000, guid: 14a3e99f4d475b64990c89f22f1e307a, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat.meta b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat.meta new file mode 100644 index 0000000..d3efd70 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Graphics/FlareMaterial.mat.meta @@ -0,0 +1,6 @@ +fileFormatVersion: 2 +guid: bc4691e301d4e4445bbd1df0a85d4006 +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator.meta b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator.meta new file mode 100644 index 0000000..295f58a --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: aa977a839fe077f44856ab4ab60094eb +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png new file mode 100644 index 0000000..9a074e3 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png.meta b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png.meta new file mode 100644 index 0000000..b13e005 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehAlpha.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: bbf784a872adaba4884518c6f1d12f4a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png new file mode 100644 index 0000000..0bad1e3 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png.meta b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png.meta new file mode 100644 index 0000000..7c9e28f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha1.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 92a2f93cd546f41428182e2dbb8b2715 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png new file mode 100644 index 0000000..514c614 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png differ diff --git a/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png.meta b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png.meta new file mode 100644 index 0000000..185d4f9 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/ImgForDirtGenerator/BokehRoundAlpha2.png.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: dd74936895f016b4b9563ce1e1593f38 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources.meta b/Assets/Cinematic Effects/BloomBeta/Resources.meta new file mode 100644 index 0000000..7841185 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 56ee327717a93674a9cba1b3d60ec916 +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip b/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip new file mode 100644 index 0000000..44d0316 Binary files /dev/null and b/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip differ diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta b/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta new file mode 100644 index 0000000..41d5f9f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/ShadersSimplified.zip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4790c2802bfcf4b4eb367eec50a925ed +timeCreated: 1456313800 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader new file mode 100644 index 0000000..7a39352 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader @@ -0,0 +1,59 @@ +Shader "Hidden/Ultimate/BokehMisc" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass // #0 Chromatic Aberration + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + half _ChromaticAberration; + + half4 frag(v2f i) : COLOR + { + half2 coords = i.uv; + half2 uv = i.uv; + + coords = (coords - 0.5) * 2.0; + half coordDot = dot (coords,coords); + + half2 uvG = uv - _MainTex_TexelSize.xy * _ChromaticAberration * coords * coordDot; + half4 color = tex2D (_MainTex, uv); + #if SHADER_API_D3D9 + // Work around Cg's code generation bug for D3D9 pixel shaders :( + color.g = color.g * 0.0001 + tex2D (_MainTex, uvG).g; + #else + color.g = tex2D (_MainTex, uvG).g; + #endif + + return color; + } + + ENDCG + } + + + + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta new file mode 100644 index 0000000..fa19fe5 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomBokehMisc.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 25b151c9a48c18747a9c043a91bedc31 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader new file mode 100644 index 0000000..c03d3dc --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader @@ -0,0 +1,337 @@ +Shader "Hidden/Ultimate/BloomCombine" { + Properties { + _MainTex ("Base (RGB)", 2D) = "black" {} + _FlareTexture ("Flare (RGB)", 2D) = "black" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment fragINV + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta new file mode 100644 index 0000000..e4b0da4 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombine.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 481edcf7070d4ba49a3e69a7161224a5 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc new file mode 100644 index 0000000..9d23080 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc @@ -0,0 +1,147 @@ + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta new file mode 100644 index 0000000..d4c6305 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineCore.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8630408eab779e24fb43f1ede27bbcf2 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader new file mode 100644 index 0000000..238aa88 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader @@ -0,0 +1,342 @@ +Shader "Hidden/Ultimate/BloomCombineFlareDirt" { + Properties { + _MainTex ("Base (RGB)", 2D) = "black" {} + _FlareTexture ("Flare (RGB)", 2D) = "black" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #define ULTIMATE_USE_FLARE + #define ULTIMATE_USE_DIRT + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #define ULTIMATE_USE_FLARE + #define ULTIMATE_USE_DIRT + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +// Curve mapping +half4 _Toe; +half4 _Shoulder; +half _K; +half _Crossover; +float Map(half x) +{ + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; +} + + +sampler2D _MainTex; +sampler2D _FlareTexture; +sampler2D _ColorBuffer; +sampler2D _AdditiveTexture; +sampler2D _brightTexture; +half _Intensity; +half _FlareIntensity; +half _DirtIntensity; +half _DirtLightIntensity; +half _ScreenMaxIntensity; + + +inline float ComputeLuma( float3 c ) +{ + return dot( c, fixed3(0.299, 0.587, 0.114) ); +} + + +fixed4 frag(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + + half4 bloom = addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + half intensity = dot(screencolor, half3(0.3,0.3,0.3)); + + float colLuma = ComputeLuma(x); + + //colLuma *= _uTAA_Exposure; + half bloomIntensity = x/max(1.0+colLuma,0.001); + + //half bloomIntensity = Map(intensity); + bloom *= screencolor * bloomIntensity/intensity*2000; +#endif + +#ifdef ULTIMATE_USE_FLARE + bloom += tex2D(_FlareTexture, i.uv); /* _FlareIntensity;*/ +#endif + + bloom *= _Intensity; + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); + +#endif + + + + + return bloom + screencolor; + + +} + +fixed4 fragINV(v2f i):COLOR +{ + half4 addedbloom = tex2D(_MainTex, i.uv); + + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + + half4 bloom = _Intensity * addedbloom; + +#ifdef ULTIMATE_BLOOM_CURVE + bloom.x = Map(bloom.x); + bloom.y = Map(bloom.y); + bloom.z = Map(bloom.z); +#endif + +#ifdef ULTIMATE_USE_FLARE + + bloom += tex2D(_FlareTexture, i.uv); + + /*half3 flare = tex2D(_FlareTexture, i.uv).rgb * 40; + half3 flareIntensity = dot(half3(0.3,0.3,0.3),flare); + half flareFactor = saturate(flareIntensity ); + bloom.xyz = lerp(bloom.xyz, flare, flareFactor);*/ + + //bloom += tex2D(_FlareTexture, i.uv) * 5; +#endif + +#ifdef ULTIMATE_USE_DIRT + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb; + + float dirtIntensity = dot(dirt.xyz, half3(0.3,0.3,0.3)); + float bloomIntensity = dot(bloom.xyz, half3(0.3,0.3,0.3)); + float factor = saturate(bloomIntensity * dirtIntensity * _DirtIntensity); + + bloom.xyz *= (dirt*_DirtIntensity + _DirtLightIntensity*0.2); +#endif + + return bloom + screencolor; + +} + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment fragINV + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta new file mode 100644 index 0000000..a407f94 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomCombineFlareDirt.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f0ecc1337a36c4f48871c943fddaed12 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader new file mode 100644 index 0000000..e8d87a3 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader @@ -0,0 +1,108 @@ +Shader "Hidden/Ultimate/BloomMixer" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass // #0 Blend Add + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + sampler2D _ColorBuffer; + half _Intensity; + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, i.uv); + return _Intensity * addedbloom + screencolor; + } + + ENDCG + } + + Pass // #1 Blend With Intensity + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + sampler2D _ColorBuffer; + half _Intensity0; + half _Intensity1; + + fixed4 frag(v2f i):COLOR + { + half4 tex0 = tex2D(_MainTex, i.uv); + half4 tex1 = tex2D(_ColorBuffer, i.uv); + return tex0 * _Intensity0 + tex1 * _Intensity1; + } + + ENDCG + } + + Pass // #2 Blit with intensity + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + + sampler2D _MainTex; + half _Intensity; + + fixed4 frag(v2f i):COLOR + { + half4 tex = tex2D(_MainTex, i.uv); + return tex * _Intensity; + } + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta new file mode 100644 index 0000000..b943ae7 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomMixer.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9a9192f3e87433946bcfb49c036c997d +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader new file mode 100644 index 0000000..4841a4d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader @@ -0,0 +1,488 @@ +Shader "Hidden/Ultimate/Bloom" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + _AdditiveTexture ("Base (RGB)", 2D) = "black" {} + _OffsetInfos ("HorizontalOffset", Vector) = (0.0,0.0,0.0,0.0) + } + + CGINCLUDE + + #pragma target 3.0 + + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + struct v2f_opts + { + half4 pos : SV_POSITION; + half2 uv[7] : TEXCOORD0; + }; + + uniform half4 _MainTex_TexelSize; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + + + float4 _OffsetInfos; + sampler2D _MainTex; + half _Intensity; + sampler2D _ColorBuffer; + sampler2D _AdditiveTexture; + sampler2D _FlareTexture; + half4 _Threshhold; + + float Gaussian(float Scale, int iSamplePoint) + { + float sigma = (Scale-1.0)/5; + float g = 1.0f / sqrt(2.0f * 3.14159 * sigma * sigma); + return (g * exp(-(iSamplePoint * iSamplePoint) / (2 * sigma * sigma))); + } + + + half4 fragGaussBlurHigh (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += Gaussian(Scale, 0.0 + Offset) * tex2D (_MainTex, gUV); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8.0); + color += Gaussian(Scale, 9.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9.0); + color += Gaussian(Scale, 9.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9.0); + color += Gaussian(Scale, 10.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10.0); + color += Gaussian(Scale, 10.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10.0); + color += Gaussian(Scale, 11.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11.0); + color += Gaussian(Scale, 11.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11.0); + color += Gaussian(Scale, 12.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 12.0); + color += Gaussian(Scale, 12.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 12.0); + color += Gaussian(Scale, 13.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 13.0); + color += Gaussian(Scale, 13.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 13.0); + color += Gaussian(Scale, 14.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 14.0); + color += Gaussian(Scale, 14.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 14.0); + color += Gaussian(Scale, 15.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 15.0); + color += Gaussian(Scale, 15.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 15.0); + + return color + tex2D(_AdditiveTexture, i.uv); + } + + half4 fragGaussBlurMedium (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 17; + + float2 gUV = i.uv; + float Offset = 0; + + color += Gaussian(Scale, 0.0 + Offset) * tex2D (_MainTex, gUV); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 5.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 6.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 7.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8.0); + color += Gaussian(Scale, 8.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8.0); + + return color + tex2D(_AdditiveTexture, i.uv); + } + + half4 fragGaussBlurLow (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 9; + + float2 gUV = i.uv; + float Offset = 0; + + color += Gaussian(Scale, 0.0 + Offset) * tex2D (_MainTex, gUV); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 1.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 2.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 3.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += Gaussian(Scale, 4.0 + Offset) * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + + return color + tex2D(_AdditiveTexture, i.uv); + } + + ENDCG + + SubShader + { + Pass // #0 Simple Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + + + float2 UV[4]; + + UV[0] = i.uv + float2(-1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[1] = i.uv + float2( 1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[2] = i.uv + float2(-1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + + + fixed4 Sample[4]; + + for(int j = 0; j < 4; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2] + Sample[3]) * 1.0/4; + } + + ENDCG + } + + Pass // #1 Gaussian Sampling High + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurHigh + + ENDCG + } + + Pass // #2 Gaussian Sampling Medium + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurMedium + + ENDCG + } + + Pass // #3 Gaussian Sampling Low + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurLow + + ENDCG + } + + Pass // #4 Color Brightpass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + + fixed4 frag(v2f i):COLOR + { + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + //half intensity = dot(tColor, float3(0.212671, 0.71516, 0.072169)); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return color * intensity; + } + + ENDCG + } + + Pass // #5 Blend Add + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, i.uv); + return _Intensity * addedbloom + screencolor; + } + + ENDCG + } + + Pass // #6 Blend Screen + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, i.uv); + return _Intensity * addedbloom + screencolor; + } + + ENDCG + } + + Pass // #7 Add One One + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + Blend One One + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + half4 addedColors = tex2D(_MainTex, i.uv.xy); + return addedColors * _Intensity; + } + + ENDCG + } + + Pass // #8 Render Flare + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + half4 _FlareScales; + half4 _FlareTint0; + half4 _FlareTint1; + half4 _FlareTint2; + half4 _FlareTint3; + + half2 cUV(half2 uv) + { + return 2.0 * uv - float2(1.0,1.0); + } + + half2 tUV(half2 uv) + { + return (uv + float2(1.0,1.0))*0.5; + } + + fixed4 frag(v2f i):COLOR + { + half scale0 = _FlareScales.x;//1.1f; + half scale1 = _FlareScales.y;//0.95f; + half scale2 = _FlareScales.z;//0.75f; + half scale3 = _FlareScales.w;//0.55f; + + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 col0 = tex2D(_MainTex, tUV(flareUv*scale0) ) * _FlareTint0; + float4 col1 = tex2D(_MainTex, tUV(flareUv*scale1) ) * _FlareTint1; + float4 col2 = tex2D(_MainTex, tUV(flareUv*scale2) ) * _FlareTint2; + float4 col3 = tex2D(_MainTex, tUV(flareUv*scale3) ) * _FlareTint3; + + // Optional..­. + flareUv = cUV(i.uv); + float4 col4 = tex2D(_MainTex, tUV(flareUv*scale0) ) * _FlareTint0; + float4 col5 = tex2D(_MainTex, tUV(flareUv*scale1) ) * _FlareTint1; + float4 col6 = tex2D(_MainTex, tUV(flareUv*scale2) ) * _FlareTint2; + float4 col7 = tex2D(_MainTex, tUV(flareUv*scale3) ) * _FlareTint3; + + return (col0 + col1 + col2 + col3 + col4 + col5 + col6 + col7) * tex2D(_FlareTexture,i.uv); + } + + ENDCG + } + + Pass // #9 Blend Add with flares + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + half _FlareIntensity; + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + //half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,i.uv.y)); + half4 bloom = _Intensity * addedbloom + tex2D(_FlareTexture, i.uv) * _FlareIntensity; + + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb * bloom * 1000; + //bloom.rgb -= dirt; + return bloom + screencolor + float4(dirt,1.0) ; + } + + ENDCG + } + + Pass // #10 Complex Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + + + float2 UV[9]; + + UV[0] = i.uv; + + UV[1] = i.uv + float2( -2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[2] = i.uv + float2( 0.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[4] = i.uv + float2( -2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[5] = i.uv + float2( 0.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[6] = i.uv + float2( 2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[7] = i.uv + float2( -2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + UV[8] = i.uv + float2( 2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + + + fixed4 Sample[9]; + + for(int j = 0; j < 9; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2] + Sample[3] + Sample[4] + Sample[5] + Sample[6] + Sample[7] + Sample[8]) * 1.0/9; + } + + ENDCG + } + + Pass // #11 Blend Add with flares Inverted Source (for forward MSAA) + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + half _FlareIntensity; + + fixed4 frag(v2f i):COLOR + { + half4 addedbloom = tex2D(_MainTex, i.uv); + half4 screencolor = tex2D(_ColorBuffer, float2(i.uv.x,1- i.uv.y)); + half4 bloom = _Intensity * addedbloom + tex2D(_FlareTexture, i.uv) * _FlareIntensity; + + half3 dirt = tex2D(_AdditiveTexture, i.uv).rgb * bloom * 1000; + return bloom + screencolor + float4(dirt,1.0) ; + } + + ENDCG + } + + } + + FallBack off +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta new file mode 100644 index 0000000..dc4260d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBloomShader.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ab676bda447e26b43b1479fa93ae8d8b +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader new file mode 100644 index 0000000..f54429f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader @@ -0,0 +1,72 @@ +// Unlit alpha-blended shader. +// - no lighting +// - no lightmap support +// - no per-material color + +Shader "Hidden/Ultimate/BokehTexture" { +Properties { + _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {} + + _Intensity ("Intensity", Float) = 1 +} + +SubShader { + Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} + LOD 100 + + Cull Off + ZWrite Off + //Blend SrcAlpha One + Blend SrcAlpha OneMinusSrcAlpha + + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + + #include "UnityCG.cginc" + + float4x4 _MeshProjectionMatrix; + float4x4 _MeshTransformationMatrix; + half _Intensity; + + + struct v2f { + float4 vertex : SV_POSITION; + half2 texcoord : TEXCOORD0; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + half4 _Tint; + + v2f vert (appdata_full v) + { + v2f o; + //o.vertex = mul(_MeshTransformationMatrix, v.vertex); + //o.vertex = mul(_MeshProjectionMatrix, v.vertex); + + o.vertex = v.vertex; + + o.texcoord = v.texcoord; + + + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.texcoord); + + + col.xyz *= _Tint; + col.a *= _Intensity; + + return col; + } + ENDCG + } +} + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta new file mode 100644 index 0000000..90ee8ef --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBokehTexture.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 239f6fb2ba87e0147bd6ade6d10111a9 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc new file mode 100644 index 0000000..001db58 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc @@ -0,0 +1,44 @@ +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +sampler2D _MainTex; +sampler2D _MaskTex; +half4 _Threshhold; + +fixed4 frag(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return clamp(color * intensity * tex2D(_MaskTex, i.uv).r,0,65000); +} + +fixed4 fragNOI(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + + return half4(tColor, 1.0) * tex2D(_MaskTex, i.uv).r; + +} + + + + + diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta new file mode 100644 index 0000000..910ed42 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassCore.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ced9b82dce9c754d9cbcffaee39e640 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader new file mode 100644 index 0000000..731d9c9 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader @@ -0,0 +1,131 @@ +Shader "Hidden/Ultimate/BrightpassMask" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MaskTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +sampler2D _MainTex; +sampler2D _MaskTex; +half4 _Threshhold; + +fixed4 frag(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return clamp(color * intensity * tex2D(_MaskTex, i.uv).r,0,65000); +} + +fixed4 fragNOI(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + + return half4(tColor, 1.0) * tex2D(_MaskTex, i.uv).r; + +} + + + + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +sampler2D _MainTex; +sampler2D _MaskTex; +half4 _Threshhold; + +fixed4 frag(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + half intensity = dot(tColor, half3(0.3,0.3,0.3)); + + return clamp(color * intensity * tex2D(_MaskTex, i.uv).r,0,65000); +} + +fixed4 fragNOI(v2f i):COLOR +{ + half4 color = tex2D(_MainTex, i.uv); + + half3 tColor = max(half3(0,0,0), color.rgb-_Threshhold.rgb); + + return half4(tColor, 1.0) * tex2D(_MaskTex, i.uv).r; + +} + + + + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment fragNOI + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta new file mode 100644 index 0000000..0d22629 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateBrightpassMask.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68bd60cbcc102e3459b4065ed54e526b +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc new file mode 100644 index 0000000..7926079 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc @@ -0,0 +1,95 @@ + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv0 : TEXCOORD1; + half4 uv1 : TEXCOORD2; + half4 uv2 : TEXCOORD3; + half4 uv3 : TEXCOORD4; +}; + + + +sampler2D _MainTex; +sampler2D _FlareTexture; +half _Intensity; + +half4 _FlareScales; +half4 _FlareScalesNear; +half4 _FlareTint0; +half4 _FlareTint1; +half4 _FlareTint2; +half4 _FlareTint3; +half4 _FlareTint4; +half4 _FlareTint5; +half4 _FlareTint6; +half4 _FlareTint7; + +half2 cUV(half2 uv) +{ + return 2.0 * uv - float2(1.0,1.0); +} + +half2 tUV(half2 uv) +{ + return (uv + float2(1.0,1.0))*0.5; +} + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + half scale0 = _FlareScales.x; + half scale1 = _FlareScales.y; + half scale2 = _FlareScales.z; + half scale3 = _FlareScales.w; + + half2 flareUv = cUV(half2(1.0,1.0) - o.uv); + o.uv0.xy = tUV(flareUv*scale0); + o.uv1.xy = tUV(flareUv*scale1); + o.uv2.xy = tUV(flareUv*scale2); + o.uv3.xy = tUV(flareUv*scale3); + + half scale4 = _FlareScalesNear.x; + half scale5 = _FlareScalesNear.y; + half scale6 = _FlareScalesNear.z; + half scale7 = _FlareScalesNear.w; + + flareUv = cUV(o.uv); + o.uv0.zw = tUV(flareUv*scale4); + o.uv1.zw = tUV(flareUv*scale5); + o.uv2.zw = tUV(flareUv*scale6); + o.uv3.zw = tUV(flareUv*scale7); + + return o; +} + +fixed4 frag(v2f i):COLOR +{ + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 acc = float4(0,0,0,0); + + acc += tex2D(_MainTex, i.uv0.xy ) * _FlareTint0; + acc += tex2D(_MainTex, i.uv1.xy ) * _FlareTint1; + acc += tex2D(_MainTex, i.uv2.xy ) * _FlareTint2; + acc += tex2D(_MainTex, i.uv3.xy ) * _FlareTint3; + +#ifdef FLARE_DOUBLE + flareUv = cUV(i.uv); + + acc += tex2D(_MainTex, i.uv0.zw ) * _FlareTint4; + acc += tex2D(_MainTex, i.uv1.zw ) * _FlareTint5; + acc += tex2D(_MainTex, i.uv2.zw ) * _FlareTint6; + acc += tex2D(_MainTex, i.uv3.zw ) * _FlareTint7; +#endif + + return clamp(acc *_Intensity,0, 65000); +} + + diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta new file mode 100644 index 0000000..70b4163 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareCore.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 734a7bdac9cb2e64e8a8d013f9aec730 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader new file mode 100644 index 0000000..db1b84c --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader @@ -0,0 +1,123 @@ +Shader "Hidden/Ultimate/FlareDouble" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #define FLARE_DOUBLE + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv0 : TEXCOORD1; + half4 uv1 : TEXCOORD2; + half4 uv2 : TEXCOORD3; + half4 uv3 : TEXCOORD4; +}; + + + +sampler2D _MainTex; +sampler2D _FlareTexture; +half _Intensity; + +half4 _FlareScales; +half4 _FlareScalesNear; +half4 _FlareTint0; +half4 _FlareTint1; +half4 _FlareTint2; +half4 _FlareTint3; +half4 _FlareTint4; +half4 _FlareTint5; +half4 _FlareTint6; +half4 _FlareTint7; + +half2 cUV(half2 uv) +{ + return 2.0 * uv - float2(1.0,1.0); +} + +half2 tUV(half2 uv) +{ + return (uv + float2(1.0,1.0))*0.5; +} + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + half scale0 = _FlareScales.x; + half scale1 = _FlareScales.y; + half scale2 = _FlareScales.z; + half scale3 = _FlareScales.w; + + half2 flareUv = cUV(half2(1.0,1.0) - o.uv); + o.uv0.xy = tUV(flareUv*scale0); + o.uv1.xy = tUV(flareUv*scale1); + o.uv2.xy = tUV(flareUv*scale2); + o.uv3.xy = tUV(flareUv*scale3); + + half scale4 = _FlareScalesNear.x; + half scale5 = _FlareScalesNear.y; + half scale6 = _FlareScalesNear.z; + half scale7 = _FlareScalesNear.w; + + flareUv = cUV(o.uv); + o.uv0.zw = tUV(flareUv*scale4); + o.uv1.zw = tUV(flareUv*scale5); + o.uv2.zw = tUV(flareUv*scale6); + o.uv3.zw = tUV(flareUv*scale7); + + return o; +} + +fixed4 frag(v2f i):COLOR +{ + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 acc = float4(0,0,0,0); + + acc += tex2D(_MainTex, i.uv0.xy ) * _FlareTint0; + acc += tex2D(_MainTex, i.uv1.xy ) * _FlareTint1; + acc += tex2D(_MainTex, i.uv2.xy ) * _FlareTint2; + acc += tex2D(_MainTex, i.uv3.xy ) * _FlareTint3; + +#ifdef FLARE_DOUBLE + flareUv = cUV(i.uv); + + acc += tex2D(_MainTex, i.uv0.zw ) * _FlareTint4; + acc += tex2D(_MainTex, i.uv1.zw ) * _FlareTint5; + acc += tex2D(_MainTex, i.uv2.zw ) * _FlareTint6; + acc += tex2D(_MainTex, i.uv3.zw ) * _FlareTint7; +#endif + + return clamp(acc *_Intensity,0, 65000); +} + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta new file mode 100644 index 0000000..e65deab --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareDouble.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 82d5870d890eb51468257e24b9f26478 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader new file mode 100644 index 0000000..5dd29ee --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader @@ -0,0 +1,52 @@ +Shader "Hidden/Ultimate/FlareMask" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MaskTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + sampler2D _MainTex; + sampler2D _MaskTex; + + + fixed4 frag(v2f i):COLOR + { + return tex2D(_MainTex, i.uv) * tex2D(_MaskTex, i.uv).r; + } + + ENDCG + } + + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta new file mode 100644 index 0000000..217ca61 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMask.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b6119eaa372f3504a92a1603c0afebc8 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader new file mode 100644 index 0000000..4390c27 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader @@ -0,0 +1,72 @@ +// Unlit alpha-blended shader. +// - no lighting +// - no lightmap support +// - no per-material color + +Shader "Hidden/Ultimate/FlareMesh" { +Properties { + _MainTex ("Base (RGB) Trans (A)", 2D) = "black" {} + _BrightTexture ("Base (RGB) Trans (A)", 2D) = "black" {} +} + +SubShader { + Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} + LOD 100 + + Cull Off + ZWrite Off + Blend SrcAlpha One + + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + #pragma glsl + + #include "UnityCG.cginc" + + float4x4 _FlareProj; + half _Intensity; + + + struct v2f { + float4 vertex : SV_POSITION; + half2 texcoord : TEXCOORD0; + half3 color : TEXCOORD1; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + sampler2D _BrightTexture; + + v2f vert (appdata_full v) + { + v2f o; + //o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); + o.vertex = mul(_FlareProj, v.vertex); + o.texcoord = v.texcoord; + + half3 bloom = tex2Dlod(_BrightTexture, float4(v.texcoord1.xy,0,0) ).xyz; + o.color = bloom * _Intensity; + + half intensity = dot(half3(0.3,0.3,0.3), o.color.xyz); + if (intensity < 0.001) + o.vertex = half4(-10000,-10000,0.0,1.0); + + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.texcoord); + col.xyz *= i.color.xyz; + + return col; + + } + ENDCG + } +} + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta new file mode 100644 index 0000000..75cda44 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareMeshShader.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: abe4898237b1d4d49b8a3ebc0f5b4d49 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader new file mode 100644 index 0000000..dcf776e --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader @@ -0,0 +1,121 @@ +Shader "Hidden/Ultimate/FlareSingle" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + Subshader + { + Pass + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + +#include "UnityCG.cginc" + +struct v2f +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv0 : TEXCOORD1; + half4 uv1 : TEXCOORD2; + half4 uv2 : TEXCOORD3; + half4 uv3 : TEXCOORD4; +}; + + + +sampler2D _MainTex; +sampler2D _FlareTexture; +half _Intensity; + +half4 _FlareScales; +half4 _FlareScalesNear; +half4 _FlareTint0; +half4 _FlareTint1; +half4 _FlareTint2; +half4 _FlareTint3; +half4 _FlareTint4; +half4 _FlareTint5; +half4 _FlareTint6; +half4 _FlareTint7; + +half2 cUV(half2 uv) +{ + return 2.0 * uv - float2(1.0,1.0); +} + +half2 tUV(half2 uv) +{ + return (uv + float2(1.0,1.0))*0.5; +} + +v2f vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + half scale0 = _FlareScales.x; + half scale1 = _FlareScales.y; + half scale2 = _FlareScales.z; + half scale3 = _FlareScales.w; + + half2 flareUv = cUV(half2(1.0,1.0) - o.uv); + o.uv0.xy = tUV(flareUv*scale0); + o.uv1.xy = tUV(flareUv*scale1); + o.uv2.xy = tUV(flareUv*scale2); + o.uv3.xy = tUV(flareUv*scale3); + + half scale4 = _FlareScalesNear.x; + half scale5 = _FlareScalesNear.y; + half scale6 = _FlareScalesNear.z; + half scale7 = _FlareScalesNear.w; + + flareUv = cUV(o.uv); + o.uv0.zw = tUV(flareUv*scale4); + o.uv1.zw = tUV(flareUv*scale5); + o.uv2.zw = tUV(flareUv*scale6); + o.uv3.zw = tUV(flareUv*scale7); + + return o; +} + +fixed4 frag(v2f i):COLOR +{ + half2 flareUv = cUV(float2(1.0,1.0) - i.uv); + + float4 acc = float4(0,0,0,0); + + acc += tex2D(_MainTex, i.uv0.xy ) * _FlareTint0; + acc += tex2D(_MainTex, i.uv1.xy ) * _FlareTint1; + acc += tex2D(_MainTex, i.uv2.xy ) * _FlareTint2; + acc += tex2D(_MainTex, i.uv3.xy ) * _FlareTint3; + +#ifdef FLARE_DOUBLE + flareUv = cUV(i.uv); + + acc += tex2D(_MainTex, i.uv0.zw ) * _FlareTint4; + acc += tex2D(_MainTex, i.uv1.zw ) * _FlareTint5; + acc += tex2D(_MainTex, i.uv2.zw ) * _FlareTint6; + acc += tex2D(_MainTex, i.uv3.zw ) * _FlareTint7; +#endif + + return clamp(acc *_Intensity,0, 65000); +} + + + + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma vertex vert + #pragma fragment frag + + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta new file mode 100644 index 0000000..2f3c551 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateFlareSingle.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 079e3a5c047c057468f404709ddfe3dc +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader new file mode 100644 index 0000000..2a1e4d3 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader @@ -0,0 +1,751 @@ +Shader "Hidden/Ultimate/Sampling" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + CGINCLUDE + + #pragma target 3.0 + + #include "UnityCG.cginc" + + float4 _OffsetInfos; + float4 _Tint; + float _Intensity; + sampler2D _MainTex; + sampler2D _AdditiveTexture; + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + struct v2f_opts + { + half4 pos : SV_POSITION; + half2 uv[7] : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + struct v2fLow { + half4 pos : POSITION; + half2 uv : TEXCOORD0; + half4 uv01 : TEXCOORD1; + half4 uv23 : TEXCOORD2; + half4 uv45 : TEXCOORD3; + half4 uv67 : TEXCOORD4; + half4 uv89 : TEXCOORD5; + }; + + + v2fLow vertLow( appdata_img v ) + { + v2fLow o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + o.uv01 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1); + o.uv23 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 2; + o.uv45 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 3; + o.uv67 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 4; + o.uv89 = v.texcoord.xyxy + _OffsetInfos.xyxy * half4(1,1, -1,-1) * 5; + + return o; + } + + inline float ComputeLuma( float3 c ) + { + return dot( c, fixed3(0.299, 0.587, 0.114) ); + } + + + float Gaussian(float Scale, int iSamplePoint) + { + float sigma = (Scale-1.0)/5; + float g = 1.0f / sqrt(2.0f * 3.14159 * sigma * sigma); + return (g * exp(-(iSamplePoint * iSamplePoint) / (2 * sigma * sigma))); + } + + float4 Upsample(half2 uv) + { + half4 f0 = tex2D (_AdditiveTexture, uv + half2(_OffsetInfos.z,_OffsetInfos.w)); + half4 f1 = tex2D (_AdditiveTexture, uv + half2(-_OffsetInfos.z,_OffsetInfos.w)); + half4 f2 = tex2D (_AdditiveTexture, uv + half2(-_OffsetInfos.z,-_OffsetInfos.w)); + half4 f3 = tex2D (_AdditiveTexture, uv + half2(_OffsetInfos.z,-_OffsetInfos.w)); + + return (f0+f1+f2+f3)*0.25; + } + + + half4 fragGaussBlurVeryHigh (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.1480461 * tex2D (_MainTex, gUV); + color += 0.1451146 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.1451146 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1366637 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1366637 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1236585 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1236585 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.1075035 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.1075035 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.08979447 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.08979447 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.07206175 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.07206175 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.05556333 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.05556333 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.04116233 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.04116233 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + color += 0.02929812 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9); + color += 0.02929812 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9); + color += 0.02003586 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10); + color += 0.02003586 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10); + color += 0.01316449 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11); + color += 0.01316449 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11); + color += 0.008310529 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 12); + color += 0.008310529 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 12); + color += 0.005040591 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 13); + color += 0.005040591 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 13); + color += 0.002937396 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 14); + color += 0.002937396 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 14); + color += 0.001644643 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 15); + color += 0.001644643 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 15); + + + color.a = 1.0; + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurHigher (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.1562562 * tex2D (_MainTex, gUV); + color += 0.1527989 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.1527989 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1428793 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1428793 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1277568 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1277568 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.1092358 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.1092358 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.08931243 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.08931243 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.06982721 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.06982721 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.05220396 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.05220396 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.03732055 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.03732055 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + color += 0.02551284 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9); + color += 0.02551284 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9); + color += 0.01667767 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10); + color += 0.01667767 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10); + color += 0.01042505 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11); + color += 0.01042505 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11); + color += 0.006231415 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 12); + color += 0.006231415 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 12); + color += 0.003561732 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 13); + color += 0.003561732 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 13); + + + color.a = 1.0; + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurHigh (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 31; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.1820341 * tex2D (_MainTex, gUV); + color += 0.1764335 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.1764335 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1606445 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1606445 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1374065 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1374065 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.1104092 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.1104092 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.08334126 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.08334126 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.05909781 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.05909781 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.03936763 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.03936763 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.02463563 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.02463563 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + color += 0.01448254 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 9); + color += 0.01448254 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 9); + color += 0.007998019 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 10); + color += 0.007998019 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 10); + color += 0.004149318 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 11); + color += 0.004149318 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 11); + + + color.a = 1.0; + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurMedium (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 17; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.2605744 * tex2D (_MainTex, gUV); + color += 0.242882 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.242882 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.1966919 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.1966919 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.13839 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.13839 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.08459612 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.08459612 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.04492867 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.04492867 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.02073118 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.02073118 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + color += 0.008310967 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 7); + color += 0.008310967 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 7); + color += 0.002894721 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 8); + color += 0.002894721 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 8); + + + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurLow (v2f i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float Scale = 17; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.3098615 * tex2D (_MainTex, gUV); + color += 0.2789662 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1); + color += 0.2789662 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1); + color += 0.2035652 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2); + color += 0.2035652 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2); + color += 0.1203992 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3); + color += 0.1203992 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3); + color += 0.05771804 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4); + color += 0.05771804 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4); + color += 0.02242682 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 5); + color += 0.02242682 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 5); + color += 0.00706304 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 6); + color += 0.00706304 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 6); + + + return color * _Tint * _Intensity + Upsample(i.uv); + } + + half4 fragGaussBlurVeryLow (v2fLow i) : SV_Target + { + half4 color = half4 (0,0,0,0); + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.4310208 * tex2D (_MainTex, i.uv); + + color += 0.3403002 * tex2D (_MainTex, i.uv01.xy); + color += 0.3403002 * tex2D (_MainTex, i.uv01.zw); + + color += 0.1674766 * tex2D (_MainTex, i.uv23.xy); + color += 0.1674766 * tex2D (_MainTex, i.uv23.zw); + + color += 0.05137766 * tex2D (_MainTex, i.uv45.xy); + color += 0.05137766 * tex2D (_MainTex, i.uv45.zw); + + color += 0.009824769 * tex2D (_MainTex, i.uv67.xy); + color += 0.009824769 * tex2D (_MainTex, i.uv67.zw); + + return color * _Tint * _Intensity + Upsample(i.uv); + } + + + ENDCG + + SubShader + { + Pass // #0 Simple Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + float2 UV[4]; + + UV[0] = i.uv + float2(-1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[1] = i.uv + float2( 1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[2] = i.uv + float2(-1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + + + fixed4 Sample[4]; + + for(int j = 0; j < 4; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2] + Sample[3]) * 1.0/4; + } + + ENDCG + } + + Pass // #1 Complex Downscaling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + fixed4 frag(v2f i):COLOR + { + + float2 UV[9]; + + UV[0] = i.uv; + + UV[1] = i.uv + float2( -2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[2] = i.uv + float2( 0.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 2.0 * _OffsetInfos.x, -2.0 * _OffsetInfos.y); + UV[4] = i.uv + float2( -2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[5] = i.uv + float2( 0.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[6] = i.uv + float2( 2.0 * _OffsetInfos.x, 2.0 * _OffsetInfos.y); + UV[7] = i.uv + float2( -2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + UV[8] = i.uv + float2( 2.0 * _OffsetInfos.x, 0.0 * _OffsetInfos.y); + + + + fixed4 Sample[9]; + + for(int j = 0; j < 9; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + half4 sum = half4(0,0,0,0); + for(int j = 0; j < 9; ++j) + { + sum += Sample[j]; + } + + return sum* 1.0/9; + } + + ENDCG + } + + Pass // #2 Gaussian Sampling Very High + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurVeryHigh + + ENDCG + } + + Pass // #3 Gaussian Sampling Medium + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurMedium + + ENDCG + } + + Pass // #4 Gaussian Sampling Very Low + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vertLow + #pragma fragment fragGaussBlurVeryLow + + ENDCG + } + + + Pass // #5 Filmic curve sampling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + // Curve mapping + half4 _Toe; + half4 _Shoulder; + half _K; + half _Crossover; + half _MaxValue; + half _CurveExposure; + float Map(half x) + { + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; + } + + + fixed4 frag(v2f i):COLOR + { + float2 UV[4]; + + UV[0] = i.uv + float2(-1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[1] = i.uv + float2( 1.0 * _OffsetInfos.x, -1.0 * _OffsetInfos.y); + UV[2] = i.uv + float2(-1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + UV[3] = i.uv + float2( 1.0 * _OffsetInfos.x, 1.0 * _OffsetInfos.y); + + fixed4 Sample[4]; + + for(int j = 0; j < 4; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + half4 color = (Sample[0] + Sample[1] + Sample[2] + Sample[3]) * 1.0/4; + + half intensity = ComputeLuma(color); + + + + half bloomIntensity = intensity/max(1.0+intensity*_CurveExposure,0.01); + + bloomIntensity = Map(bloomIntensity) * _MaxValue; + + return clamp(color * bloomIntensity/intensity,0,65000); + } + + ENDCG + } + + Pass // #6 Low Gaussian Filmic Curve + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + // Curve mapping + half4 _Toe; + half4 _Shoulder; + half _K; + half _Crossover; + float Map(half x) + { + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; + } + + fixed4 frag(v2f i):COLOR + { + half4 color = half4 (0,0,0,0); + + float Scale = 9; + + float2 gUV = i.uv; + float Offset = 0; + + color += 0.4005 * tex2D (_MainTex, gUV); + color += 0.3294 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 1.0); + color += 0.3294 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 1.0); + color += 0.1833 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 2.0); + color += 0.1833 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 2.0); + color += 0.0691 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 3.0); + color += 0.0691 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 3.0); + color += 0.0175 * tex2D (_MainTex, gUV + _OffsetInfos.xy * 4.0); + color += 0.0175 * tex2D (_MainTex, gUV - _OffsetInfos.xy * 4.0); + + + + + half intensity = dot(color, half3(0.3,0.3,0.3)); + half bloomIntensity = Map(intensity); + + return color * bloomIntensity/intensity; + } + + ENDCG + } + + Pass // #7 Simple Blur + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + + fixed4 frag(v2f i):COLOR + { + + + float2 UV[3]; + + UV[0] = i.uv; + UV[1] = i.uv + 1.5*_OffsetInfos; + UV[2] = i.uv - 1.5*_OffsetInfos; + //UV[2] = i.uv + 2*_OffsetInfos; + //UV[3] = i.uv - 2*_OffsetInfos; + + + fixed4 Sample[3]; + + for(int j = 0; j < 3; ++j) + { + Sample[j] = tex2D(_MainTex, UV[j]); + } + + return (Sample[0] + Sample[1] + Sample[2]) * 1.0/3; + } + + ENDCG + } + + Pass // #8 Gaussian Sampling Small + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurLow + + ENDCG + } + + Pass // #9 Gaussian Sampling High + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurHigh + + ENDCG + } + + Pass // #10 Gaussian Sampling Higher + { + CGPROGRAM + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #pragma vertex vert_img + #pragma fragment fragGaussBlurHigher + + ENDCG + } + + Pass // #11 Temporal Stable Downsampling + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + float2 _MainTex_TexelSize; + + fixed4 frag(v2f i):COLOR + { + float4 offsets = _MainTex_TexelSize.xyxy * float4(-1.0, -1.0, +1.0, +1.0); + half3 c0 = tex2D(_MainTex, i.uv + offsets.xy); + half3 c1 = tex2D(_MainTex, i.uv + offsets.zy); + half3 c2 = tex2D(_MainTex, i.uv + offsets.xw); + half3 c3 = tex2D(_MainTex, i.uv + offsets.zw); + half w0 = 1.0 / (ComputeLuma(c0) + 1.0); + half w1 = 1.0 / (ComputeLuma(c1) + 1.0); + half w2 = 1.0 / (ComputeLuma(c2) + 1.0); + half w3 = 1.0 / (ComputeLuma(c3) + 1.0); + half div = 1.0 / max(w0 + w1 + w2 + w3, 0.01); + float3 color = (c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3) * div; + + return float4(clamp(color,0,65000), 1); + + //half intensity = dot(color, half3(0.3,0.3,0.3)); + + //half bloomIntensity = intensity/max(1.0+intensity*_CurveExposure,0.01); + + //return float4(clamp(color * bloomIntensity/intensity,0,65000), 1); + } + + ENDCG + } + + + Pass // #12 Temporal Stable Downsampling with filmic curve + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + float2 _MainTex_TexelSize; + + // Curve mapping + half4 _Toe; + half4 _Shoulder; + half _K; + half _Crossover; + half _MaxValue; + half _CurveExposure; + float Map(half x) + { + float4 data; + float endAdd; + + if (x > _Crossover) + { + data = _Shoulder; + endAdd = _K; + } + else + { + data = _Toe; + endAdd = 0; + } + + + float2 numDenum = data.xy * x + data.zw; + return numDenum.x / numDenum.y + endAdd; + } + + fixed4 frag(v2f i):COLOR + { + float4 offsets = _MainTex_TexelSize.xyxy * float4(-1.0, -1.0, +1.0, +1.0); + half3 c0 = tex2D(_MainTex, i.uv + offsets.xy); + half3 c1 = tex2D(_MainTex, i.uv + offsets.zy); + half3 c2 = tex2D(_MainTex, i.uv + offsets.xw); + half3 c3 = tex2D(_MainTex, i.uv + offsets.zw); + half w0 = 1.0 / (ComputeLuma(c0) + 1.0); + half w1 = 1.0 / (ComputeLuma(c1) + 1.0); + half w2 = 1.0 / (ComputeLuma(c2) + 1.0); + half w3 = 1.0 / (ComputeLuma(c3) + 1.0); + half div = 1.0 / max(w0 + w1 + w2 + w3, 0.01); + float3 color = (c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3) * div; + + half intensity = ComputeLuma(color); + + half bloomIntensity = intensity/max(1.0+intensity*_CurveExposure,0.01); + bloomIntensity = Map(bloomIntensity) * _MaxValue; + + return float4(clamp(color * bloomIntensity/intensity,0,65000), 1); + } + + ENDCG + } + + } + + FallBack off +} diff --git a/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta new file mode 100644 index 0000000..c527d0f --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Resources/UltimateSampling.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aae4bb3d598e50d4bada0867c1df4eb4 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts.meta b/Assets/Cinematic Effects/BloomBeta/Scripts.meta new file mode 100644 index 0000000..14d4900 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8d98caaa93f108b4a8be214f58dfe23f +folderAsset: yes +timeCreated: 1443580217 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs new file mode 100644 index 0000000..fe10124 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + + +class BokehRenderer +{ + Texture2D m_CurrentTexture; + //Mesh[] m_FlareMeshes = null; + Material m_FlareMaterial; + + int m_CurrentWidth; + int m_CurrentHeight; + float m_CurrentRelativeScaleX; + float m_CurrentRelativeScaleY; + + public BokehRenderer() + { + + } + + public void RebuildMeshIfNeeded(int width, int height, float spriteRelativeScaleX, float spriteRelativeScaleY, ref Mesh[] meshes) + { + if (m_CurrentWidth == width && m_CurrentHeight == height && m_CurrentRelativeScaleX == spriteRelativeScaleX && m_CurrentRelativeScaleY == spriteRelativeScaleY && meshes != null) + return; + + if (meshes != null) + foreach (Mesh m in meshes) + { + GameObject.DestroyImmediate(m, true); + } + meshes = null; + + BuildMeshes(width, height, spriteRelativeScaleX, spriteRelativeScaleY, ref meshes); + + } + + public void BuildMeshes(int width, int height, float spriteRelativeScaleX, float spriteRelativeScaleY, ref Mesh[] meshes) + { + int maxQuads = 65000 / 6; + int totalQuads = width * height; + int meshCount = Mathf.CeilToInt((1.0f * totalQuads) / (1.0f * maxQuads)); + meshes = new Mesh[meshCount]; + int currentQuads = totalQuads; + + + m_CurrentWidth = width; + m_CurrentHeight = height; + m_CurrentRelativeScaleX = spriteRelativeScaleX; + m_CurrentRelativeScaleY = spriteRelativeScaleY; + int currentPixel = 0; + + for (int m = 0; m < meshCount; ++m) + { + Mesh currentMesh = new Mesh(); + currentMesh.hideFlags = HideFlags.HideAndDontSave; + + int nbQuads = currentQuads; + if (currentQuads > maxQuads) + nbQuads = maxQuads; + currentQuads -= nbQuads; + + Vector3[] vertices = new Vector3[nbQuads * 4]; + int[] triangles = new int[nbQuads * 6]; + Vector2[] uv0 = new Vector2[nbQuads * 4]; + Vector2[] uv1 = new Vector2[nbQuads * 4]; + Vector3[] normals = new Vector3[nbQuads * 4]; + Color[] colors = new Color[nbQuads * 4]; + + float spriteWidth = m_CurrentRelativeScaleX * width; + float spriteHeigth = m_CurrentRelativeScaleY * height; + + + for (int i = 0; i < nbQuads; ++i) + { + int x = currentPixel % width; + int y = (currentPixel - x) / width; + SetupSprite(i, x, y, vertices, triangles, uv0, uv1, normals, colors, new Vector2((float)x / (float)width, 1.0f - ((float)y / (float)height)), spriteWidth * 0.5f, spriteHeigth * 0.5f); + currentPixel++; + } + + currentMesh.vertices = vertices; + currentMesh.triangles = triangles; + currentMesh.colors = colors; + currentMesh.uv = uv0; + currentMesh.uv2 = uv1; + currentMesh.normals = normals; + currentMesh.RecalculateBounds(); + currentMesh.UploadMeshData(true); + meshes[m] = currentMesh; + } + } + + public void Clear(ref Mesh[] meshes) + { + if (meshes != null) + foreach (Mesh m in meshes) + { + GameObject.DestroyImmediate(m, true); + } + meshes = null; + } + + public void SetTexture(Texture2D texture) + { + m_CurrentTexture = texture; + m_FlareMaterial.SetTexture("_MainTex", m_CurrentTexture); + } + + public void SetMaterial(Material flareMaterial) + { + m_FlareMaterial = flareMaterial; + } + + public void RenderFlare(RenderTexture brightPixels, RenderTexture destination, float intensity, ref Mesh[] meshes) + { + + RenderTexture lastActive = RenderTexture.active; + + RenderTexture.active = destination; + GL.Clear(true, true, Color.black); + + Matrix4x4 proj = Matrix4x4.Ortho(0, m_CurrentWidth, 0, m_CurrentHeight, -1.0f, 1.0f); + + m_FlareMaterial.SetMatrix("_FlareProj", proj); + m_FlareMaterial.SetTexture("_BrightTexture", brightPixels); + m_FlareMaterial.SetFloat("_Intensity", intensity); + + if (m_FlareMaterial.SetPass(0)) + { + //Debug.Log("MeshCount=" + m_FlareMeshes.Length); + + for (int i = 0; i < meshes.Length; ++i ) + Graphics.DrawMeshNow(meshes[i], Matrix4x4.identity); + } + else + { + Debug.LogError("Can't render flare mesh"); + } + + RenderTexture.active = lastActive; + + } + + public void SetupSprite(int idx, int x, int y, Vector3[] vertices, int[] triangles, Vector2[] uv0, Vector2[] uv1, Vector3[] normals, Color[] colors, Vector2 targetPixelUV, float halfWidth, float halfHeight) + { + int vIdx = idx * 4; + int tIdx = idx * 6; + + triangles[tIdx + 0] = vIdx + 0; + triangles[tIdx + 1] = vIdx + 2; + triangles[tIdx + 2] = vIdx + 1; + + triangles[tIdx + 3] = vIdx + 2; + triangles[tIdx + 4] = vIdx + 3; + triangles[tIdx + 5] = vIdx + 1; + + vertices[vIdx + 0] = new Vector3((-halfWidth + x), (-halfHeight + y), 0); + vertices[vIdx + 1] = new Vector3((halfWidth + x), (-halfHeight + y), 0); + vertices[vIdx + 2] = new Vector3((-halfWidth + x), (halfHeight + y), 0); + vertices[vIdx + 3] = new Vector3((halfWidth + x), (halfHeight + y), 0); + + Vector2 p = targetPixelUV; + + colors[vIdx + 0] = new Color((-halfWidth / m_CurrentWidth + p.x), (-halfHeight*-1/ m_CurrentHeight + p.y), 0, 0); + colors[vIdx + 1] = new Color((halfWidth / m_CurrentWidth + p.x), (-halfHeight * -1 / m_CurrentHeight + p.y), 0, 0); + colors[vIdx + 2] = new Color((-halfWidth / m_CurrentWidth + p.x), (halfHeight * -1 / m_CurrentHeight + p.y), 0, 0); + colors[vIdx + 3] = new Color((halfWidth / m_CurrentWidth + p.x), (halfHeight * -1 / m_CurrentHeight + p.y), 0, 0); + + normals[vIdx + 0] = -Vector3.forward; + normals[vIdx + 1] = -Vector3.forward; + normals[vIdx + 2] = -Vector3.forward; + normals[vIdx + 3] = -Vector3.forward; + + uv0[vIdx + 0] = new Vector2(0, 0); + uv0[vIdx + 1] = new Vector2(1.0f, 0); + uv0[vIdx + 2] = new Vector2(0, 1.0f); + uv0[vIdx + 3] = new Vector2(1.0f, 1.0f); + + uv1[vIdx + 0] = targetPixelUV; + uv1[vIdx + 1] = targetPixelUV; + uv1[vIdx + 2] = targetPixelUV; + uv1[vIdx + 3] = targetPixelUV; + } + + + +} + diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta new file mode 100644 index 0000000..27b1699 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/BokehRenderer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f26e82e850c24c444bb8306feb47738d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs new file mode 100644 index 0000000..2fd397c --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs @@ -0,0 +1,241 @@ +using UnityEngine; +using System.Collections; +using System; +using UnityEditor; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +[Serializable] +public class DeluxeFilmicCurve +{ + [SerializeField] + public float m_BlackPoint = 0.0f; + + [SerializeField] + public float m_WhitePoint = 1.0f; + + [SerializeField] + public float m_CrossOverPoint = 0.3f; + + [SerializeField] + public float m_ToeStrength = 0.98f; + + [SerializeField] + public float m_ShoulderStrength = 0.0f; + + [SerializeField] + public float m_Highlights = 0.5f; + + public float m_k; + public Vector4 m_ToeCoef; + public Vector4 m_ShoulderCoef; + + public float GetExposure() + { + float highlights = m_Highlights; + float exposure = 2.0f + (1.0f - highlights) * 20.0f; + return (exposure * Mathf.Exp(-2.0f)); + } + + public float ComputeK(float t, float c, float b, float s, float w) + { + float num = (1 - t) * (c - b); + float denom = (1 - s) * (w - c) + (1 - t) * (c - b); + + return num / denom; + } + + public float Toe(float x, float t, float c, float b, float s, float w, float k) + { + float xnum = m_ToeCoef.x * x; + float xdenom = m_ToeCoef.y * x; + + return (xnum + m_ToeCoef.z) / (xdenom + m_ToeCoef.w); + + /*float num = k * (1 - t) * (x - b); + float denom = c - (1 - t) * b - t * x; + + return num / denom;*/ + } + + public float Shoulder(float x, float t, float c, float b, float s, float w, float k) + { + float xnum = m_ShoulderCoef.x * x; + float xdenom = m_ShoulderCoef.y * x; + + return (xnum + m_ShoulderCoef.z) / (xdenom + m_ShoulderCoef.w) + k; + + /*float num = (1 - k) * (x - c); + float denom = s*x + (1 - s) * w - c; + + return num / denom + k;*/ + } + + public float Graph(float x, float t, float c, float b, float s, float w, float k) + { + if (x <= m_CrossOverPoint) + return Toe(x, t, c, b, s, w, k); + + return Shoulder(x, t, c, b, s, w, k); + } + + public void StoreK() + { + m_k = ComputeK(m_ToeStrength, m_CrossOverPoint, m_BlackPoint, m_ShoulderStrength, m_WhitePoint); + } + + public void ComputeShaderCoefficients(float t, float c, float b, float s, float w, float k) + { + { + float xNumMul = k * (1 - t); + float numAdd = k * (1 - t) * -b; + float xDenomMul = -t; + float denomAdd = c - (1 - t) * b; + m_ToeCoef = new Vector4(xNumMul, xDenomMul, numAdd, denomAdd); + } + + { + float xNumMul = (1 - k); + float numAdd = (1 - k) * -c; + float xDenomMul = s; + float denomAdd = (1 - s) * w - c; + m_ShoulderCoef = new Vector4(xNumMul, xDenomMul, numAdd, denomAdd); + } + } + + public void UpdateCoefficients() + { + StoreK(); + ComputeShaderCoefficients(m_ToeStrength, m_CrossOverPoint, m_BlackPoint, m_ShoulderStrength, m_WhitePoint, m_k); + } + + + + + Vector3[] m_CurvePoints; + + void DrawCurve() + { + //Rect rr = GUILayoutUtility.GetRect(Mathf.Min(r.width, 60), 60); + //if (m_CurvePoints != null) + { + const int h = 100; + const int h1 = h - 1; + Rect rect; + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + rect = GUILayoutUtility.GetRect(Mathf.Max(EditorGUIUtility.currentViewWidth - 50.0f, 10.0f), h); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + GUI.Box(rect, GUIContent.none); + + int nbPoint = 40; + int w = Mathf.FloorToInt(rect.width); + + Vector3[] points = new Vector3[nbPoint]; + + for (int i = 0; i < nbPoint; i++) + { + float norm = (float)i / (float)nbPoint; + float value = Graph(norm * m_WhitePoint, m_ToeStrength, m_CrossOverPoint, m_BlackPoint, m_ShoulderStrength, m_WhitePoint, m_k); + value = Mathf.Clamp01(value); + points[i] = new Vector3(rect.x + i * (float)w / (float)(nbPoint - 1), rect.y + (h - value * h1), 0f); + } + + + Handles.color = Color.green; + Handles.DrawAAPolyLine(2f, points); + } + //EditorGUI.CurveField(rr, m_Curve); + } + + public void OnGUI() + { + //SetupCurve(); + + float denom = m_WhitePoint - m_BlackPoint; + + float co = (m_CrossOverPoint - m_BlackPoint) / denom; + if (Mathf.Abs(denom) < 0.001f) + co = 0.5f; + + EditorGUILayout.LabelField("Curve Parameters", EditorStyles.boldLabel); + m_WhitePoint = 1.0f; + m_BlackPoint = 0.0f; + co = DoSlider("Middle", co, 0.0f, 1.0f); + m_ToeStrength = -1.0f * DoSlider("Dark", -1.0f * m_ToeStrength, -0.99f, 0.99f); + m_ShoulderStrength = DoSlider("Bright", m_ShoulderStrength, -0.99f, 0.99f); + m_Highlights = DoSlider("Highlights", m_Highlights, 0.0f, 1.0f); + + m_CrossOverPoint = co * (m_WhitePoint - m_BlackPoint) + m_BlackPoint; + UpdateCoefficients(); + + EditorGUILayout.BeginVertical(GUILayout.MinHeight(60)); + // Curve drawing + DrawCurve(); + EditorGUILayout.EndVertical(); + } + + AnimationCurve m_Curve; + + private static float CalculateLinearTangent(AnimationCurve curve, int index, int toIndex) + { + return (float)(((double)curve[index].value - (double)curve[toIndex].value) / ((double)curve[index].time - (double)curve[toIndex].time)); + } + + void SetupCurve() + { + m_Curve = new AnimationCurve(); + + DeluxeFilmicCurve dt = this; + + float min = dt.m_BlackPoint; + float max = dt.m_WhitePoint; + + int nbFrame = 40; + float step = (max - min) / nbFrame; + + m_CurvePoints = new Vector3[nbFrame + 1]; + + float curr = min; + float k = dt.ComputeK(dt.m_ToeStrength, dt.m_CrossOverPoint, dt.m_BlackPoint, dt.m_ShoulderStrength, dt.m_WhitePoint); + + dt.StoreK(); + dt.ComputeShaderCoefficients(dt.m_ToeStrength, dt.m_CrossOverPoint, dt.m_BlackPoint, dt.m_ShoulderStrength, dt.m_WhitePoint, k); + + for (int i = 0; i < nbFrame + 1; ++i) + { + float value = dt.Graph(curr, dt.m_ToeStrength, dt.m_CrossOverPoint, dt.m_BlackPoint, dt.m_ShoulderStrength, dt.m_WhitePoint, k); + + m_CurvePoints[i] = new Vector3(curr, value); + + m_Curve.AddKey(new Keyframe(curr, value)); + + curr += step; + } + + for (int i = 0; i < m_Curve.keys.Length - 1; ++i) + { + float tangent = CalculateLinearTangent(m_Curve, i, i + 1); + m_Curve.keys[i].inTangent = tangent; + m_Curve.keys[i].outTangent = tangent; + + m_Curve.SmoothTangents(i, 0.0f); + } + } + + float DoSlider(string label, float value, float min, float max) + { + float v = value; + EditorGUILayout.BeginHorizontal(); + v = Mathf.Clamp(EditorGUILayout.FloatField(label, v), min, max); + v = GUILayout.HorizontalSlider(v, min, max); + EditorGUILayout.EndHorizontal(); + + return v; + } + +} diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta new file mode 100644 index 0000000..50d545d --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/DeluxeFilmicCurve.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 4b47c958d5706f24d8fc004492f16384 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs new file mode 100644 index 0000000..797b6d7 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs @@ -0,0 +1,84 @@ +using UnityEngine; +using System.Collections; + +public class UBHelper : MonoBehaviour +{ + + static UBHelper() + { + s_Styles = new Styles(); + } + + public static bool GroupHeader(string text, bool isExpanded) + { + Rect rect = GUILayoutUtility.GetRect(16f, 22f, s_Styles.header); + + s_Styles.Backup(); + s_Styles.Apply(); + + if (Event.current.type == EventType.Repaint) + s_Styles.header.Draw(rect, text, isExpanded, isExpanded, isExpanded, isExpanded); + + Event e = Event.current; + if (e.type == EventType.MouseDown) + { + if (rect.Contains(e.mousePosition)) + { + isExpanded = !isExpanded; + e.Use(); + } + } + + s_Styles.Revert(); + return isExpanded; + } + + private static Styles s_Styles; + private class Styles + { + public GUIStyle header = "ShurikenModuleTitle"; + public GUIStyle headerArrow = "AC RightArrow"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + } + + RectOffset m_Border; + float m_FixedHeight; + Vector2 m_ContentOffset; + TextAnchor m_TextAlign; + FontStyle m_TextStyle; + int m_FontSize; + + public void Backup() + { + m_Border = s_Styles.header.border; + m_FixedHeight = s_Styles.header.fixedHeight; + m_ContentOffset = s_Styles.header.contentOffset; + m_TextAlign = s_Styles.header.alignment; + m_TextStyle = s_Styles.header.fontStyle; + m_FontSize = s_Styles.header.fontSize; + } + + public void Apply() + { + s_Styles.header.border = new RectOffset(7, 7, 4, 4); + s_Styles.header.fixedHeight = 22; + s_Styles.header.contentOffset = new Vector2(20f, -2f); + s_Styles.header.alignment = TextAnchor.MiddleLeft; + s_Styles.header.fontStyle = FontStyle.Bold; + s_Styles.header.fontSize = 12; + } + + public void Revert() + { + s_Styles.header.border = m_Border; + s_Styles.header.fixedHeight = m_FixedHeight; + s_Styles.header.contentOffset = m_ContentOffset; + s_Styles.header.alignment = m_TextAlign; + s_Styles.header.fontStyle = m_TextStyle; + s_Styles.header.fontSize = m_FontSize; + } + } +} diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta new file mode 100644 index 0000000..493d597 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UBHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 68539e60785f1d44c8848e40b66f760f +timeCreated: 1456307053 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs new file mode 100644 index 0000000..4ec9961 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs @@ -0,0 +1,1568 @@ +using UnityEngine; +using System.Collections; +using System; +#if UNITY_EDITOR +using UnityEditor; +using System.IO; +#endif + +[ExecuteInEditMode] +[RequireComponent(typeof(Camera))] +public class UltimateBloom : MonoBehaviour +{ + + public enum BloomQualityPreset + { + Optimized, + Standard, + HighVisuals, + Custom + } + + public enum BloomSamplingQuality + { + VerySmallKernel, // 9 + SmallKernel, // 13 + MediumKernel, // 17 + LargeKernel, // 23 + LargerKernel, // 27 + VeryLargeKernel // 31 + } + + public enum BloomScreenBlendMode + { + Screen = 0, + Add = 1, + } + + public enum HDRBloomMode + { + Auto = 0, + On = 1, + Off = 2, + } + + public enum BlurSampleCount + { + Nine, + Seventeen, + Thirteen, + TwentyThree, + TwentySeven, + ThrirtyOne, + NineCurve, + FourSimple + } + + public enum FlareRendering + { + Sharp, + Blurred, + MoreBlurred + } + + public enum SimpleSampleCount + { + Four, + Nine, + FourCurve, + ThirteenTemporal, + ThirteenTemporalCurve + } + + public enum FlareType + { + Single, + Double + } + + public enum BloomIntensityManagement + { + FilmicCurve, + Threshold + } + + private enum FlareStripeType + { + Anamorphic, + Star, + DiagonalUpright, + DiagonalUpleft + } + + public enum AnamorphicDirection + { + Horizontal, + Vertical + } + + public enum BokehFlareQuality + { + Low, + Medium, + High, + VeryHigh + } + + public enum BlendMode + { + ADD, + SCREEN + } + + public enum SamplingMode + { + Fixed, + HeightRelative + } + + public enum FlareBlurQuality + { + Fast, + Normal, + High + } + + public enum FlarePresets + { + ChoosePreset, + GhostFast, + Ghost1, + Ghost2, + Ghost3, + Bokeh1, + Bokeh2, + Bokeh3 + } + + + + public float m_SamplingMinHeight = 400.0f; + public float[] m_ResSamplingPixelCount = new float[6]; + + public SamplingMode m_SamplingMode = SamplingMode.Fixed; + + public BlendMode m_BlendMode = BlendMode.ADD; + public float m_ScreenMaxIntensity; + + public BloomQualityPreset m_QualityPreset; + + public HDRBloomMode m_HDR = HDRBloomMode.Auto; + + public BloomScreenBlendMode m_ScreenBlendMode = BloomScreenBlendMode.Add; + + public float m_BloomIntensity = 1.0f; + + public float m_BloomThreshhold = 0.5f; + public Color m_BloomThreshholdColor = Color.white; + public int m_DownscaleCount = 5; + public BloomIntensityManagement m_IntensityManagement = BloomIntensityManagement.FilmicCurve; + public float[] m_BloomIntensities; + public Color[] m_BloomColors; + public bool[] m_BloomUsages; + + [SerializeField] + public DeluxeFilmicCurve m_BloomCurve = new DeluxeFilmicCurve(); + + private int m_LastDownscaleCount = 5; + + public bool m_UseLensFlare = false; + public float m_FlareTreshold = 0.8f; + public float m_FlareIntensity = 0.25f; + + public Color m_FlareTint0 = new Color(137 / 255.0f, 82 / 255.0f, 0 / 255.0f); + public Color m_FlareTint1 = new Color(0 / 255.0f, 63 / 255.0f, 126 / 255.0f); + public Color m_FlareTint2 = new Color(72 / 255.0f, 151 / 255.0f, 0 / 255.0f); + public Color m_FlareTint3 = new Color(114 / 255.0f, 35 / 255.0f, 0 / 255.0f); + public Color m_FlareTint4 = new Color(122 / 255.0f, 88 / 255.0f, 0 / 255.0f); + public Color m_FlareTint5 = new Color(137 / 255.0f, 71 / 255.0f, 0 / 255.0f); + public Color m_FlareTint6 = new Color(97 / 255.0f, 139 / 255.0f, 0 / 255.0f); + public Color m_FlareTint7 = new Color(40 / 255.0f, 142 / 255.0f, 0 / 255.0f); + + public float m_FlareGlobalScale = 1.0f; + public Vector4 m_FlareScales = new Vector4(1.0f, 0.6f, 0.5f, 0.4f); + public Vector4 m_FlareScalesNear = new Vector4(1.0f, 0.8f, 0.6f, 0.5f); + public Texture2D m_FlareMask; + public FlareRendering m_FlareRendering = FlareRendering.Blurred; + public FlareType m_FlareType = FlareType.Double; + public Texture2D m_FlareShape; + public FlareBlurQuality m_FlareBlurQuality = FlareBlurQuality.High; + BokehRenderer m_FlareSpriteRenderer; + Mesh[] m_BokehMeshes; + public bool m_UseBokehFlare = false; + public float m_BokehScale = 0.4f; + //public bool m_HighQualityBokehFlare = true; + public BokehFlareQuality m_BokehFlareQuality = BokehFlareQuality.Medium; + + public bool m_UseAnamorphicFlare = false; + public float m_AnamorphicFlareTreshold = 0.8f; + public float m_AnamorphicFlareIntensity = 1.0f; + public int m_AnamorphicDownscaleCount = 3; + public int m_AnamorphicBlurPass = 2; + private int m_LastAnamorphicDownscaleCount; + private RenderTexture[] m_AnamorphicUpscales; + public float[] m_AnamorphicBloomIntensities; + public Color[] m_AnamorphicBloomColors; + public bool[] m_AnamorphicBloomUsages; + public bool m_AnamorphicSmallVerticalBlur = true; + public AnamorphicDirection m_AnamorphicDirection = AnamorphicDirection.Horizontal; + public float m_AnamorphicScale = 3.0f; + + + public bool m_UseStarFlare = false; + public float m_StarFlareTreshol = 0.8f; + public float m_StarFlareIntensity = 1.0f; + public float m_StarScale = 2.0f; + public int m_StarDownscaleCount = 3; + public int m_StarBlurPass = 2; + private int m_LastStarDownscaleCount; + private RenderTexture[] m_StarUpscales; + public float[] m_StarBloomIntensities; + public Color[] m_StarBloomColors; + public bool[] m_StarBloomUsages; + + public bool m_UseLensDust = false; + public float m_DustIntensity = 1.0f; + public Texture2D m_DustTexture; + public float m_DirtLightIntensity = 5.0f; + + public BloomSamplingQuality m_DownsamplingQuality; + public BloomSamplingQuality m_UpsamplingQuality; + public bool m_TemporalStableDownsampling = true; + + + // Misc + public bool m_InvertImage = false; + + + // Materials/shaders + private Material m_FlareMaterial; + private Shader m_FlareShader; + private Material m_SamplingMaterial; + private Shader m_SamplingShader; + private Material m_CombineMaterial; + private Shader m_CombineShader; + private Material m_BrightpassMaterial; + private Shader m_BrightpassShader; + private Material m_FlareMaskMaterial; + private Shader m_FlareMaskShader; + private Material m_MixerMaterial; + private Shader m_MixerShader; + + private Material m_FlareBokehMaterial; + private Shader m_FlareBokehShader; + + // Optimization + public bool m_DirectDownSample = false; + public bool m_DirectUpsample = false; + + // UI + public bool m_UiShowBloomScales = false; + public bool m_UiShowAnamorphicBloomScales = false; + public bool m_UiShowStarBloomScales = false; + public bool m_UiShowHeightSampling = false; + + + public bool m_UiShowBloomSettings = false; + public bool m_UiShowSampling = false; + public bool m_UiShowIntensity = false; + public bool m_UiShowOptimizations = false; + public bool m_UiShowLensDirt = false; + public bool m_UiShowLensFlare = false; + public bool m_UiShowAnamorphic = false; + public bool m_UiShowStar = false; + +#if UNITY_EDITOR + public bool m_UiInitialized = false; + void OnEnable() + { + if (!m_UiInitialized && !Application.isPlaying) + { + m_UiInitialized = true; + IntializeUltimateBloom(); + } + } + + public static string GetAbsoluteAssetPath(string path) + { + UltimateBloomPathLocator locator = ScriptableObject.CreateInstance(); + MonoScript script = MonoScript.FromScriptableObject(locator); + string scriptPath = AssetDatabase.GetAssetPath(script); + ScriptableObject.DestroyImmediate(locator); + return Path.GetDirectoryName(scriptPath) + "/" + path; + } + + private void IntializeUltimateBloom() + { + CreateMaterials(); + + m_BloomUsages[0] = false; + m_AnamorphicBloomUsages[0] = true; + m_AnamorphicBloomUsages[1] = true; + m_StarBloomUsages[0] = true; + m_StarBloomUsages[1] = true; + m_UpsamplingQuality = UltimateBloom.BloomSamplingQuality.SmallKernel; + + string flareMaskPath = GetAbsoluteAssetPath("Graphics/FlareMask.png"); + Texture2D flareMask = (Texture2D)AssetDatabase.LoadAssetAtPath(flareMaskPath, typeof(Texture2D)); + m_FlareMask = flareMask; + + string bokehPath = GetAbsoluteAssetPath("Graphics/Bokeh.png"); + Texture2D bokeh = (Texture2D)AssetDatabase.LoadAssetAtPath(bokehPath, typeof(Texture2D)); + m_FlareShape = bokeh; + + string dustPath = GetAbsoluteAssetPath("DirtTextureSample/Dust.tif"); + Texture2D dust = (Texture2D)AssetDatabase.LoadAssetAtPath(dustPath, typeof(Texture2D)); + m_DustTexture = dust; + + m_BloomCurve.UpdateCoefficients(); + } +#endif + + + private void DestroyMaterial(Material mat) + { + if (mat) + { + DestroyImmediate(mat); + mat = null; + } + } + + private void LoadShader(ref Material material, ref Shader shader, string shaderPath) + { + if (shader != null) + return; + shader = Shader.Find(shaderPath); + if (shader == null) + { + Debug.LogError("Shader not found: " + shaderPath); + return; + } + + + if (!shader.isSupported) + { + Debug.LogError("Shader contains error: " + shaderPath + "\n Maybe include path? Try rebuilding the shader."); + return; + } + + material = CreateMaterial(shader); + } + + public void CreateMaterials() + { + //m_FlareType = FlareType.Double; + int maxScaleCount = 8; + if (m_BloomIntensities == null || m_BloomIntensities.Length < maxScaleCount) + { + m_BloomIntensities = new float[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_BloomIntensities[i] = 1.0f; + } + if (m_BloomColors == null || m_BloomColors.Length < maxScaleCount) + { + m_BloomColors = new Color[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_BloomColors[i] = Color.white; + } + if (m_BloomUsages == null || m_BloomUsages.Length < maxScaleCount ) + { + m_BloomUsages = new bool[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_BloomUsages[i] = true; + } + + if (m_AnamorphicBloomIntensities == null || m_AnamorphicBloomIntensities.Length < maxScaleCount) + { + m_AnamorphicBloomIntensities = new float[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_AnamorphicBloomIntensities[i] = 1.0f; + } + if (m_AnamorphicBloomColors == null || m_AnamorphicBloomColors.Length < maxScaleCount) + { + m_AnamorphicBloomColors = new Color[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_AnamorphicBloomColors[i] = Color.white; + } + if (m_AnamorphicBloomUsages == null || m_AnamorphicBloomUsages.Length < maxScaleCount ) + { + m_AnamorphicBloomUsages = new bool[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_AnamorphicBloomUsages[i] = true; + } + + if (m_StarBloomIntensities == null || m_StarBloomIntensities.Length < maxScaleCount) + { + m_StarBloomIntensities = new float[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_StarBloomIntensities[i] = 1.0f; + } + if (m_StarBloomColors == null || m_StarBloomColors.Length < maxScaleCount) + { + m_StarBloomColors = new Color[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_StarBloomColors[i] = Color.white; + } + if (m_StarBloomUsages == null || m_StarBloomUsages.Length < maxScaleCount) + { + m_StarBloomUsages = new bool[maxScaleCount]; + for (int i = 0; i < 8; ++i) + m_StarBloomUsages[i] = true; + } + + if (m_FlareSpriteRenderer == null && m_FlareShape != null && m_UseBokehFlare) + { + if (m_FlareSpriteRenderer != null) + m_FlareSpriteRenderer.Clear(ref m_BokehMeshes); + + m_FlareSpriteRenderer = new BokehRenderer(); + } + + if (m_SamplingMaterial == null) + { + m_DownSamples = new RenderTexture[GetNeededDownsamples()]; + m_UpSamples = new RenderTexture[m_DownscaleCount]; + m_AnamorphicUpscales = new RenderTexture[m_AnamorphicDownscaleCount]; + m_StarUpscales = new RenderTexture[m_StarDownscaleCount]; + } + + string flareShaderPath = m_FlareType == FlareType.Single ? "Hidden/Ultimate/FlareSingle" : "Hidden/Ultimate/FlareDouble"; + LoadShader(ref m_FlareMaterial, ref m_FlareShader, flareShaderPath); + + LoadShader(ref m_SamplingMaterial, ref m_SamplingShader, "Hidden/Ultimate/Sampling"); + LoadShader(ref m_BrightpassMaterial, ref m_BrightpassShader, "Hidden/Ultimate/BrightpassMask"); + LoadShader(ref m_FlareMaskMaterial, ref m_FlareMaskShader, "Hidden/Ultimate/FlareMask"); + LoadShader(ref m_MixerMaterial, ref m_MixerShader, "Hidden/Ultimate/BloomMixer"); + LoadShader(ref m_FlareBokehMaterial, ref m_FlareBokehShader, "Hidden/Ultimate/FlareMesh"); + + bool useDustOrFlare = m_UseLensDust || m_UseLensFlare || m_UseAnamorphicFlare || m_UseStarFlare; + + string combineShaderPath = "Hidden/Ultimate/BloomCombine"; + if (useDustOrFlare) + combineShaderPath = "Hidden/Ultimate/BloomCombineFlareDirt"; + + LoadShader(ref m_CombineMaterial, ref m_CombineShader, combineShaderPath); + } + + private Material CreateMaterial(Shader shader) + { + if (!shader) + return null; + Material m = new Material(shader); + m.hideFlags = HideFlags.HideAndDontSave; + return m; + } + + void OnDisable() + { + ForceShadersReload(); + if (m_FlareSpriteRenderer != null) + { + m_FlareSpriteRenderer.Clear(ref m_BokehMeshes); + m_FlareSpriteRenderer = null; + } + } + + public void ForceShadersReload() + { + DestroyMaterial(m_FlareMaterial); m_FlareMaterial = null; m_FlareShader = null; + DestroyMaterial(m_SamplingMaterial); m_SamplingMaterial = null; m_SamplingShader = null; + DestroyMaterial(m_CombineMaterial); m_CombineMaterial = null; m_CombineShader = null; + DestroyMaterial(m_BrightpassMaterial); m_BrightpassMaterial = null; m_BrightpassShader = null; + DestroyMaterial(m_FlareBokehMaterial); m_FlareBokehMaterial = null; m_FlareBokehShader = null; + DestroyMaterial(m_FlareMaskMaterial); m_FlareMaskMaterial = null; m_FlareMaskShader = null; + DestroyMaterial(m_MixerMaterial); m_MixerMaterial = null; m_MixerShader = null; + } + + + private RenderTexture[] m_DownSamples; + private RenderTexture[] m_UpSamples; + + int GetNeededDownsamples() + { + int m = Mathf.Max(m_DownscaleCount, m_UseAnamorphicFlare ? m_AnamorphicDownscaleCount : 0); + m = Mathf.Max(m, m_UseLensFlare ? GetGhostBokehLayer() + 1 : 0); + m = Mathf.Max(m, m_UseStarFlare ? m_StarDownscaleCount : 0); + + return m; + } + + private RenderTextureFormat m_Format; + + + bool[] m_BufferUsage; + void ComputeBufferOptimization() + { + if (m_BufferUsage == null) + m_BufferUsage = new bool[m_DownSamples.Length]; + if (m_BufferUsage.Length != m_DownSamples.Length) + m_BufferUsage = new bool[m_DownSamples.Length]; + + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = false; + + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = m_BloomUsages[i] ? true : m_BufferUsage[i]; + + if (m_UseAnamorphicFlare) + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = m_AnamorphicBloomUsages[i] ? true : m_BufferUsage[i]; + + if (m_UseStarFlare) + for (int i = 0; i < m_BufferUsage.Length; ++i) + m_BufferUsage[i] = m_StarBloomUsages[i] ? true : m_BufferUsage[i]; + } + + int GetGhostBokehLayer() + { + if (m_UseBokehFlare && m_FlareShape != null) + { + if (m_BokehFlareQuality == BokehFlareQuality.VeryHigh) + return 1; + if (m_BokehFlareQuality == BokehFlareQuality.High) + return 2; + if (m_BokehFlareQuality == BokehFlareQuality.Medium) + return 3; + if (m_BokehFlareQuality == BokehFlareQuality.Low) + return 4; + } + return 0;// Ghost + } + + BlurSampleCount GetUpsamplingSize() + { + if (m_SamplingMode == SamplingMode.Fixed) + { + BlurSampleCount upsamplingCount = BlurSampleCount.ThrirtyOne; + if (m_UpsamplingQuality == BloomSamplingQuality.VerySmallKernel) + upsamplingCount = BlurSampleCount.Nine; + else if (m_UpsamplingQuality == BloomSamplingQuality.SmallKernel) + upsamplingCount = BlurSampleCount.Thirteen; + else if (m_UpsamplingQuality == BloomSamplingQuality.MediumKernel) + upsamplingCount = BlurSampleCount.Seventeen; + else if (m_UpsamplingQuality == BloomSamplingQuality.LargeKernel) + upsamplingCount = BlurSampleCount.TwentyThree; + else if (m_UpsamplingQuality == BloomSamplingQuality.LargerKernel) + upsamplingCount = BlurSampleCount.TwentySeven; + return upsamplingCount; + } + + float pixelCount = Screen.height;//Screen.width * Screen.height; + int nearestIdx = 0; + float nearestDist = float.MaxValue; + for (int i = 0; i < m_ResSamplingPixelCount.Length; ++i) + { + float dist = Math.Abs(pixelCount - m_ResSamplingPixelCount[i]); + if (dist < nearestDist) + { + nearestDist = dist; + nearestIdx = i; + } + } + + if (nearestIdx == 0) + return BlurSampleCount.Nine; + if (nearestIdx == 1) + return BlurSampleCount.Thirteen; + if (nearestIdx == 2) + return BlurSampleCount.Seventeen; + if (nearestIdx == 3) + return BlurSampleCount.TwentyThree; + if (nearestIdx == 4) + return BlurSampleCount.TwentySeven; + + return BlurSampleCount.ThrirtyOne; + } + + + public void ComputeResolutionRelativeData() + { + float currentRes = m_SamplingMinHeight; + float currentSampling = 9.0f; + for (int i = 0; i < m_ResSamplingPixelCount.Length; ++i) + { + m_ResSamplingPixelCount[i] = currentRes; + + float nextSampling = currentSampling + 4.0f; + float ratio = nextSampling / currentSampling; + currentRes *= ratio; + currentSampling = nextSampling; + } + } + + void OnRenderImage(RenderTexture source, RenderTexture destination) + { + + // Determine Texture Format + bool doHdr = false; + if (m_HDR == HDRBloomMode.Auto) + doHdr = source.format == RenderTextureFormat.ARGBHalf && GetComponent().hdr; + else + doHdr = m_HDR == HDRBloomMode.On; + + m_Format = (doHdr) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.Default; + + + if (m_DownSamples != null) + { + if (m_DownSamples.Length != GetNeededDownsamples()) + { + OnDisable(); + } + } + + + if (m_LastDownscaleCount != m_DownscaleCount + || m_LastAnamorphicDownscaleCount != m_AnamorphicDownscaleCount + || m_LastStarDownscaleCount != m_StarDownscaleCount) + { + OnDisable(); + } + m_LastDownscaleCount = m_DownscaleCount; + m_LastAnamorphicDownscaleCount = m_AnamorphicDownscaleCount; + m_LastStarDownscaleCount = m_StarDownscaleCount; + + CreateMaterials(); + + + + if (m_DirectDownSample || m_DirectUpsample) + ComputeBufferOptimization(); + + bool debugFlareShape = false; + + if (m_SamplingMode == SamplingMode.HeightRelative) + ComputeResolutionRelativeData(); + + + ////////////////////////////////// + // 1. Bright pass + ////////////////////////////////// + RenderTexture brightTexture = RenderTexture.GetTemporary(source.width, source.height, 0, m_Format); + brightTexture.filterMode = FilterMode.Bilinear; + + if (m_IntensityManagement == BloomIntensityManagement.Threshold) + BrightPass(source, brightTexture, m_BloomThreshhold * m_BloomThreshholdColor); + else + { + m_BloomCurve.UpdateCoefficients(); + Graphics.Blit(source, brightTexture); + } + + + + ////////////////////////////////// + // 2. Downscale source texture + ////////////////////////////////// + if (m_IntensityManagement == BloomIntensityManagement.Threshold) + CachedDownsample(brightTexture, m_DownSamples, null, doHdr); + else + CachedDownsample(brightTexture, m_DownSamples, m_BloomCurve, doHdr); + + ////////////////////////////////// + // 3. Upsample + ////////////////////////////////// + // Upsampling quality + BlurSampleCount upsamplingCount = GetUpsamplingSize(); + // Upsample + CachedUpsample(m_DownSamples, m_UpSamples, source.width, source.height, upsamplingCount); + // Release unused upsamples + /* if (m_DirectUpsample) + { + for (int i = 1; i < m_UpSamples.Length; ++i) + if (m_BufferUsage[i]) + RenderTexture.ReleaseTemporary(m_UpSamples[i]); + } + else*/ + + + //for (int i = 1; i < m_UpSamples.Length; ++i) + // RenderTexture.ReleaseTemporary(m_UpSamples[i]); + + + ////////////////////////////////// + // Optional: Ghost lens flare + ////////////////////////////////// + + Texture flareRT = Texture2D.blackTexture; + RenderTexture flareShapeBuffer = null; + if (m_UseLensFlare) + { + int bokehQuality = GetGhostBokehLayer(); + + int flareWidth = source.width / (int)Mathf.Pow(2.0f, bokehQuality); + int flareHeigth = source.height / (int)Mathf.Pow(2.0f, bokehQuality); + + if (m_FlareShape != null && m_UseBokehFlare) + { + float size = 15.0f; + if (m_BokehFlareQuality == BokehFlareQuality.Medium) + size *= 2; + if (m_BokehFlareQuality == BokehFlareQuality.High) + size *= 4; + if (m_BokehFlareQuality == BokehFlareQuality.VeryHigh) + size *= 8; + + size *= m_BokehScale; + m_FlareSpriteRenderer.SetMaterial(m_FlareBokehMaterial); + m_FlareSpriteRenderer.RebuildMeshIfNeeded(flareWidth, flareHeigth, 1.0f / flareWidth * size, 1.0f / flareHeigth * size, ref m_BokehMeshes); + m_FlareSpriteRenderer.SetTexture(m_FlareShape); + + flareShapeBuffer = RenderTexture.GetTemporary(source.width / 4 , source.height / 4 , 0, m_Format); + + int bokehTargetSize = bokehQuality; + RenderTexture flareBrightTexture = RenderTexture.GetTemporary(source.width / (int)Mathf.Pow(2.0f, (bokehTargetSize + 1)), source.height / (int)Mathf.Pow(2.0f, (bokehTargetSize + 1)), 0, m_Format); + BrightPass(m_DownSamples[bokehQuality], flareBrightTexture, m_FlareTreshold * Vector4.one); + m_FlareSpriteRenderer.RenderFlare(flareBrightTexture, flareShapeBuffer, m_UseBokehFlare ? 1.0f : m_FlareIntensity, ref m_BokehMeshes); + RenderTexture.ReleaseTemporary(flareBrightTexture); + + RenderTexture maskFlare = RenderTexture.GetTemporary(flareShapeBuffer.width, flareShapeBuffer.height, 0, m_Format); + m_FlareMaskMaterial.SetTexture("_MaskTex", m_FlareMask); + Graphics.Blit(flareShapeBuffer, maskFlare, m_FlareMaskMaterial, 0); + + RenderTexture.ReleaseTemporary(flareShapeBuffer); flareShapeBuffer = null; + RenderFlares(maskFlare, source, ref flareRT); + RenderTexture.ReleaseTemporary(maskFlare); + } + else + { + //BrightPassWithMask(source, brightTexture, m_FlareTreshold * Vector4.one, m_FlareMask); + //RenderFlares( brightTexture, source, ref flareRT); + int ghostLayer = GetGhostBokehLayer(); + RenderTexture flareSource = m_DownSamples[ghostLayer]; + RenderTexture flareBrightTexture = RenderTexture.GetTemporary(flareSource.width, flareSource.height, 0, m_Format); + + BrightPassWithMask(m_DownSamples[ghostLayer], flareBrightTexture, m_FlareTreshold * Vector4.one, m_FlareMask); + RenderFlares(flareBrightTexture, source, ref flareRT); + + RenderTexture.ReleaseTemporary(flareBrightTexture); + } + + + } + + if (!m_UseLensFlare && m_FlareSpriteRenderer != null) + m_FlareSpriteRenderer.Clear(ref m_BokehMeshes); + + ////////////////////////////////// + // Optional: Anamorphic lens flare + ////////////////////////////////// + if (m_UseAnamorphicFlare) + { + RenderTexture anamorphicResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.Anamorphic); + + if (anamorphicResult != null) + { + if (m_UseLensFlare) + { + RenderTextureAdditive(anamorphicResult, (RenderTexture)flareRT, 1.0f); + RenderTexture.ReleaseTemporary(anamorphicResult); + } + else + { + flareRT = anamorphicResult; + } + } + } + + ////////////////////////////////// + // Optional: Star lens flare + ////////////////////////////////// + if (m_UseStarFlare) + { + //RenderTexture starResult = RenderStar(m_DownSamples, upsamplingCount, source.width, source.height); + RenderTexture starResult = null; + + if (m_StarBlurPass == 1) + { + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.Star); + + if (starResult != null) + { + if (m_UseLensFlare || m_UseAnamorphicFlare) + { + RenderTextureAdditive(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + } + else + { + flareRT = RenderTexture.GetTemporary(source.width, source.height, 0, m_Format); + BlitIntensity(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + } + + RenderTexture.ReleaseTemporary(starResult); + } + } + else + { + if (m_UseLensFlare || m_UseAnamorphicFlare) + { + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpright); + if (starResult != null) + { + RenderTextureAdditive(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + RenderTexture.ReleaseTemporary(starResult); + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpleft); + + RenderTextureAdditive(starResult, (RenderTexture)flareRT, m_StarFlareIntensity); + RenderTexture.ReleaseTemporary(starResult); + } + } + else + { + starResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpleft); + if (starResult != null) + { + RenderTexture tmpStarResult = RenderStripe(m_DownSamples, upsamplingCount, source.width, source.height, FlareStripeType.DiagonalUpright); + CombineAdditive(tmpStarResult, starResult, m_StarFlareIntensity, m_StarFlareIntensity); + RenderTexture.ReleaseTemporary(tmpStarResult); + + flareRT = starResult; + } + } + } + + + } + + // Release downsamples + if (m_DirectDownSample) + for (int i = 0; i < m_DownSamples.Length; ++i) + { + if (m_BufferUsage[i]) + RenderTexture.ReleaseTemporary(m_DownSamples[i]); + } + else + for (int i = 0; i < m_DownSamples.Length; ++i) + RenderTexture.ReleaseTemporary(m_DownSamples[i]); + + ////////////////////////////////// + // Combine pass + ////////////////////////////////// + m_CombineMaterial.SetFloat("_Intensity", m_BloomIntensity); + + m_CombineMaterial.SetFloat("_FlareIntensity", m_FlareIntensity); + m_CombineMaterial.SetTexture("_ColorBuffer", source); + m_CombineMaterial.SetTexture("_FlareTexture", flareRT); + m_CombineMaterial.SetTexture("_AdditiveTexture", m_UseLensDust ? m_DustTexture : Texture2D.whiteTexture); + m_CombineMaterial.SetTexture("_brightTexture", brightTexture); + if (m_UseLensDust) + { + m_CombineMaterial.SetFloat("_DirtIntensity", m_DustIntensity); + m_CombineMaterial.SetFloat("_DirtLightIntensity", m_DirtLightIntensity); + } + else + { + m_CombineMaterial.SetFloat("_DirtIntensity", 1.0f); + m_CombineMaterial.SetFloat("_DirtLightIntensity", 0.0f); + } + + + if (m_BlendMode == BlendMode.SCREEN) + { + m_CombineMaterial.SetFloat("_ScreenMaxIntensity", m_ScreenMaxIntensity); + } + + if (m_InvertImage) + Graphics.Blit(m_LastBloomUpsample, destination, m_CombineMaterial, 1); + else + Graphics.Blit(m_LastBloomUpsample, destination, m_CombineMaterial, 0); + + + for (int i = 0; i < m_UpSamples.Length; ++i) + if (m_UpSamples[i] != null) + RenderTexture.ReleaseTemporary(m_UpSamples[i]); + + //Graphics.Blit(m_UpSamples[0], destination); + + ////////////////////////////////// + // Cleaning + ////////////////////////////////// + + if (debugFlareShape) + Graphics.Blit(flareShapeBuffer, destination); + + + if (m_UseLensFlare || m_UseAnamorphicFlare || m_UseStarFlare) + if (flareRT != null && flareRT is RenderTexture) + RenderTexture.ReleaseTemporary((RenderTexture)flareRT); + + RenderTexture.ReleaseTemporary(brightTexture); + + if (m_FlareShape != null && m_UseBokehFlare && flareShapeBuffer != null) + { + RenderTexture.ReleaseTemporary(flareShapeBuffer); + } + } + + RenderTexture RenderStar(RenderTexture[] sources, BlurSampleCount upsamplingCount, int sourceWidth, int sourceHeight) + { + for (int i = m_StarUpscales.Length - 1; i >= 0; --i) + { + m_StarUpscales[i] = RenderTexture.GetTemporary(sourceWidth / (int)Mathf.Pow(2.0f, i), sourceHeight / (int)Mathf.Pow(2.0f, i), 0, m_Format); + m_StarUpscales[i].filterMode = FilterMode.Bilinear; + + float horizontalBlur = 1.0f / sources[i].width; + float verticalBlur = 1.0f / sources[i].height; + + if (i < m_StarDownscaleCount - 1) + GaussianBlur2(sources[i], m_StarUpscales[i], horizontalBlur * m_StarScale, verticalBlur * m_StarScale, m_StarUpscales[i + 1], upsamplingCount, Color.white, 1.0f); + else + GaussianBlur2(sources[i], m_StarUpscales[i], horizontalBlur * m_StarScale, verticalBlur * m_StarScale, null, upsamplingCount, Color.white, 1.0f); + } + + for (int i = 1; i < m_StarUpscales.Length; ++i) + if (m_StarUpscales[i] != null) + RenderTexture.ReleaseTemporary(m_StarUpscales[i]); + + return m_StarUpscales[0]; + + } + + delegate void BlurFunction(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity); + + RenderTexture RenderStripe(RenderTexture[] sources, BlurSampleCount upsamplingCount, int sourceWidth, int sourceHeight, FlareStripeType type) + { + + + + //BlurFunction blur = GaussianBlur1; + //int nbUpscales = m_AnamorphicUpscales.Length; + RenderTexture[] upscales = m_AnamorphicUpscales; + bool[] usages = m_AnamorphicBloomUsages; + float[] intensities = m_AnamorphicBloomIntensities; + Color[] tints = m_AnamorphicBloomColors; + bool antiJitter = m_AnamorphicSmallVerticalBlur; + float blurPass = m_AnamorphicBlurPass; + float scale = m_AnamorphicScale; + float globalIntensity = m_AnamorphicFlareIntensity; + + float horiMul = 1.0f; + float vertiMul = 0.0f; + + if (m_AnamorphicDirection == AnamorphicDirection.Vertical) + { + horiMul = 0.0f; + vertiMul = 1.0f; + } + + if (type != FlareStripeType.Anamorphic) + { + // if (type == FlareStripeType.Star) + // blur = GaussianBlur2; + + //nbUpscales = m_StarUpscales.Length; + upscales = m_StarUpscales; + usages = m_StarBloomUsages; + intensities = m_StarBloomIntensities; + tints = m_StarBloomColors; + antiJitter = false; + blurPass = m_StarBlurPass; + scale = m_StarScale; + globalIntensity = m_StarFlareIntensity; + + if (type == FlareStripeType.DiagonalUpleft) + vertiMul = -1.0f; + else + vertiMul = 1.0f; + } + + for (int i = 0; i < upscales.Length; ++i) + upscales[i] = null; + + RenderTexture additiveTexture = null; + for (int i = upscales.Length - 1; i >= 0; --i) + { + if (sources[i] == null && m_DirectUpsample) + continue; + if (!usages[i] && m_DirectUpsample) + continue; + + + upscales[i] = RenderTexture.GetTemporary(sourceWidth / (int)Mathf.Pow(2.0f, i), sourceHeight / (int)Mathf.Pow(2.0f, i), 0, m_Format); + upscales[i].filterMode = FilterMode.Bilinear; + + float horizontalBlur = 1.0f / upscales[i].width; + float verticalBlur = 1.0f / upscales[i].height; + + RenderTexture source = sources[i]; + RenderTexture dest = upscales[i]; + + if (!usages[i]) + { + if (additiveTexture != null) + { + if (antiJitter) + GaussianBlur1(additiveTexture, dest, m_AnamorphicDirection == AnamorphicDirection.Vertical ? horizontalBlur : 0.0f, m_AnamorphicDirection == AnamorphicDirection.Horizontal ? verticalBlur : 0.0f, null, BlurSampleCount.FourSimple, Color.white, 1.0f); + else + Graphics.Blit(additiveTexture, dest); + } + else + Graphics.Blit(Texture2D.blackTexture, dest); + + additiveTexture = upscales[i]; + continue; + } + + RenderTexture antiJitterBuffer = null; + if (antiJitter && additiveTexture != null) + { + antiJitterBuffer = RenderTexture.GetTemporary(dest.width, dest.height, 0, m_Format); + GaussianBlur1(additiveTexture, antiJitterBuffer, m_AnamorphicDirection == AnamorphicDirection.Vertical ? horizontalBlur : 0.0f, m_AnamorphicDirection == AnamorphicDirection.Horizontal ? verticalBlur : 0.0f, null, BlurSampleCount.FourSimple, Color.white, 1.0f); + additiveTexture = antiJitterBuffer; + } + + if (blurPass == 1) + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(source, dest, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, additiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(source, dest, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, additiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + } + else + { + RenderTexture tmp = RenderTexture.GetTemporary(dest.width, dest.height, 0, m_Format); + bool lastTargetIsTmp = false; + for (int j = 0; j < blurPass; ++j) + { + RenderTexture finalAdditiveTexture = (j == blurPass - 1) ? additiveTexture : null; + + if (j == 0) + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(source, tmp, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(source, tmp, horizontalBlur * scale * horiMul, verticalBlur * scale * vertiMul, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + } + else + { + horizontalBlur = 1.0f / dest.width; + verticalBlur = 1.0f / dest.height; + if (j % 2 == 1) + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(tmp, dest, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(tmp, dest, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + lastTargetIsTmp = false; + } + else + { + if (type != FlareStripeType.Anamorphic) + GaussianBlur2(dest, tmp, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + else + GaussianBlur1(dest, tmp, horizontalBlur * scale * horiMul * 1.5f, verticalBlur * scale * vertiMul * 1.5f, finalAdditiveTexture, upsamplingCount, tints[i], intensities[i] * globalIntensity); + lastTargetIsTmp = true; + } + } + } + if (lastTargetIsTmp) + Graphics.Blit(tmp, dest); + + if (antiJitterBuffer != null) + RenderTexture.ReleaseTemporary(antiJitterBuffer); + + + RenderTexture.ReleaseTemporary(tmp); + + } + + additiveTexture = upscales[i]; + } + + + + RenderTexture firstFound = null; + for (int i = 0; i < upscales.Length; ++i) + if (upscales[i] != null) + if (firstFound == null) firstFound = upscales[i]; + else RenderTexture.ReleaseTemporary(upscales[i]); + + return firstFound; + } + + void RenderFlares(RenderTexture brightTexture, RenderTexture source,ref Texture flareRT) + { + + flareRT = RenderTexture.GetTemporary(source.width, source.height, 0, m_Format); + flareRT.filterMode = FilterMode.Bilinear; + m_FlareMaterial.SetVector("_FlareScales", m_FlareScales * m_FlareGlobalScale); + m_FlareMaterial.SetVector("_FlareScalesNear", m_FlareScalesNear * m_FlareGlobalScale); + m_FlareMaterial.SetVector("_FlareTint0", m_FlareTint0); + m_FlareMaterial.SetVector("_FlareTint1", m_FlareTint1); + m_FlareMaterial.SetVector("_FlareTint2", m_FlareTint2); + m_FlareMaterial.SetVector("_FlareTint3", m_FlareTint3); + m_FlareMaterial.SetVector("_FlareTint4", m_FlareTint4); + m_FlareMaterial.SetVector("_FlareTint5", m_FlareTint5); + m_FlareMaterial.SetVector("_FlareTint6", m_FlareTint6); + m_FlareMaterial.SetVector("_FlareTint7", m_FlareTint7); + m_FlareMaterial.SetFloat("_Intensity", m_FlareIntensity); + //Graphics.Blit(brightTexture, (RenderTexture)flareRT, m_BloomMaterial, 8); + if (m_FlareRendering == FlareRendering.Sharp) + { + RenderTexture HalfTmp = RenderTexture.GetTemporary(source.width / 2, source.height / 2, 0, m_Format); + HalfTmp.filterMode = FilterMode.Bilinear; + + RenderSimple(brightTexture, HalfTmp, 1.0f / brightTexture.width, 1.0f / brightTexture.height, SimpleSampleCount.Four); + + Graphics.Blit(HalfTmp, (RenderTexture)flareRT, m_FlareMaterial, 0); + + RenderTexture.ReleaseTemporary(HalfTmp); + + return; + } + + // Blur flare + + if (m_FlareBlurQuality == FlareBlurQuality.Fast) + { + RenderTexture HalfFlareRT = RenderTexture.GetTemporary(brightTexture.width / 2, brightTexture.height / 2, 0, m_Format); + HalfFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT = RenderTexture.GetTemporary(brightTexture.width / 4, brightTexture.height / 4, 0, m_Format); + QuarterFlareRT.filterMode = FilterMode.Bilinear; + + Graphics.Blit(brightTexture, HalfFlareRT, m_FlareMaterial, 0); + + if (m_FlareRendering == FlareRendering.Blurred) + { + GaussianBlurSeparate(HalfFlareRT, (RenderTexture)QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, null, BlurSampleCount.Thirteen, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + else if (m_FlareRendering == FlareRendering.MoreBlurred) + { + GaussianBlurSeparate(HalfFlareRT, (RenderTexture)QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, null, BlurSampleCount.ThrirtyOne, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + RenderTexture.ReleaseTemporary(HalfFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT); + return; + } + else if (m_FlareBlurQuality == FlareBlurQuality.Normal) + { + RenderTexture HalfFlareRT = RenderTexture.GetTemporary(brightTexture.width / 2, brightTexture.height / 2, 0, m_Format); + HalfFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT = RenderTexture.GetTemporary(brightTexture.width / 4, brightTexture.height / 4, 0, m_Format); + QuarterFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT2 = RenderTexture.GetTemporary(brightTexture.width / 4, brightTexture.height / 4, 0, m_Format); + QuarterFlareRT2.filterMode = FilterMode.Bilinear; + + + RenderSimple(brightTexture, HalfFlareRT, 1.0f / brightTexture.width, 1.0f / brightTexture.height, SimpleSampleCount.Four); + RenderSimple(HalfFlareRT, QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, SimpleSampleCount.Four); + + Graphics.Blit(QuarterFlareRT, QuarterFlareRT2, m_FlareMaterial, 0); + + + if (m_FlareRendering == FlareRendering.Blurred) + { + GaussianBlurSeparate(QuarterFlareRT2, (RenderTexture)QuarterFlareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, null, BlurSampleCount.Thirteen, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + else if (m_FlareRendering == FlareRendering.MoreBlurred) + { + GaussianBlurSeparate(QuarterFlareRT2, (RenderTexture)QuarterFlareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, null, BlurSampleCount.ThrirtyOne, Color.white, 1.0f); + RenderSimple(QuarterFlareRT, (RenderTexture)flareRT, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + } + + + RenderTexture.ReleaseTemporary(HalfFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT2); + } + else if (m_FlareBlurQuality == FlareBlurQuality.High) + { + RenderTexture HalfFlareRT = RenderTexture.GetTemporary(brightTexture.width / 2, brightTexture.height / 2, 0, m_Format); + HalfFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture QuarterFlareRT = RenderTexture.GetTemporary(HalfFlareRT.width / 2, HalfFlareRT.height / 2, 0, m_Format); + QuarterFlareRT.filterMode = FilterMode.Bilinear; + + RenderTexture HFlareRT1 = RenderTexture.GetTemporary(QuarterFlareRT.width / 2, QuarterFlareRT.height / 2, 0, m_Format); + HFlareRT1.filterMode = FilterMode.Bilinear; + + RenderTexture HFlareRT2 = RenderTexture.GetTemporary(QuarterFlareRT.width / 2, QuarterFlareRT.height / 2, 0, m_Format); + HFlareRT2.filterMode = FilterMode.Bilinear; + + + RenderSimple(brightTexture, HalfFlareRT, 1.0f / brightTexture.width, 1.0f / brightTexture.height, SimpleSampleCount.Four); + RenderSimple(HalfFlareRT, QuarterFlareRT, 1.0f / HalfFlareRT.width, 1.0f / HalfFlareRT.height, SimpleSampleCount.Four); + RenderSimple(QuarterFlareRT, HFlareRT1, 1.0f / QuarterFlareRT.width, 1.0f / QuarterFlareRT.height, SimpleSampleCount.Four); + + Graphics.Blit(HFlareRT1, HFlareRT2, m_FlareMaterial, 0); + + + if (m_FlareRendering == FlareRendering.Blurred) + { + GaussianBlurSeparate(HFlareRT2, (RenderTexture)HFlareRT1, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, null, BlurSampleCount.Thirteen, Color.white, 1.0f); + RenderSimple(HFlareRT1, (RenderTexture)flareRT, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, SimpleSampleCount.Four); + } + else if (m_FlareRendering == FlareRendering.MoreBlurred) + { + GaussianBlurSeparate(HFlareRT2, (RenderTexture)HFlareRT1, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, null, BlurSampleCount.ThrirtyOne, Color.white, 1.0f); + RenderSimple(HFlareRT1, (RenderTexture)flareRT, 1.0f / HFlareRT1.width, 1.0f / HFlareRT1.height, SimpleSampleCount.Four); + } + + + RenderTexture.ReleaseTemporary(HalfFlareRT); + RenderTexture.ReleaseTemporary(QuarterFlareRT); + RenderTexture.ReleaseTemporary(HFlareRT1); + RenderTexture.ReleaseTemporary(HFlareRT2); + } + + + + } + + RenderTexture m_LastBloomUpsample; + + void CachedUpsample(RenderTexture[] sources, RenderTexture[] destinations, int originalWidth, int originalHeight, BlurSampleCount upsamplingCount) + { + RenderTexture lastUpsample = null; + + for (int i = 0; i < m_UpSamples.Length; ++i) + m_UpSamples[i] = null; + + for (int i = destinations.Length - 1; i >= 0; --i) + { + if (m_BloomUsages[i] || !m_DirectUpsample) + { + m_UpSamples[i] = RenderTexture.GetTemporary(originalWidth / (int)Mathf.Pow(2.0f, i), originalHeight / (int)Mathf.Pow(2.0f, i), 0, m_Format); + m_UpSamples[i].filterMode = FilterMode.Bilinear; + } + + float mul = 1.0f; + + if (m_BloomUsages[i]) + { + float horizontalBlur = 1.0f / sources[i].width; + float verticalBlur = 1.0f / sources[i].height; + + GaussianBlurSeparate(m_DownSamples[i], m_UpSamples[i], horizontalBlur * mul, verticalBlur, lastUpsample, upsamplingCount, m_BloomColors[i], m_BloomIntensities[i]); + } + else + { + if (i < m_DownscaleCount - 1) + { + if (!m_DirectUpsample) + RenderSimple(lastUpsample, m_UpSamples[i], 1.0f / m_UpSamples[i].width, 1.0f / m_UpSamples[i].height, SimpleSampleCount.Four); + //Graphics.Blit(m_UpSamples[i + 1], m_UpSamples[i]); + } + else + Graphics.Blit(Texture2D.blackTexture, m_UpSamples[i]); + } + + if (m_BloomUsages[i] || !m_DirectUpsample) + lastUpsample = m_UpSamples[i]; + } + + m_LastBloomUpsample = lastUpsample; + } + + void CachedDownsample(RenderTexture source, RenderTexture[] destinations, DeluxeFilmicCurve intensityCurve, bool hdr) + { + int downscaleCount = destinations.Length; + + RenderTexture currentSource = source; + + bool filmicCurveDone = false; + + for (int i = 0; i < downscaleCount; ++i) + { + if (m_DirectDownSample) + { + if (!m_BufferUsage[i]) + continue; + } + + destinations[i] = RenderTexture.GetTemporary(source.width / (int)Mathf.Pow(2.0f, (i + 1)), source.height / (int)Mathf.Pow(2.0f, (i + 1)), 0, m_Format); + destinations[i].filterMode = FilterMode.Bilinear; + + RenderTexture dest = destinations[i]; + float dist = 1.0f; + + float horizontalBlur = 1.0f / currentSource.width; + float verticalBlur = 1.0f / currentSource.height; + + // Render previous into next + { + if (intensityCurve != null && !filmicCurveDone) + { + intensityCurve.StoreK(); + m_SamplingMaterial.SetFloat("_CurveExposure", intensityCurve.GetExposure()); + m_SamplingMaterial.SetFloat("_K", intensityCurve.m_k); + m_SamplingMaterial.SetFloat("_Crossover", intensityCurve.m_CrossOverPoint); + m_SamplingMaterial.SetVector("_Toe", intensityCurve.m_ToeCoef); + m_SamplingMaterial.SetVector("_Shoulder", intensityCurve.m_ShoulderCoef); + // m_SamplingMaterial.SetFloat("_MaxValue", intensityCurve.m_WhitePoint); + + + float colorRange = hdr ? 2.0f : 1.0f; + m_SamplingMaterial.SetFloat("_MaxValue", colorRange); + + horizontalBlur = 1.0f / currentSource.width; + verticalBlur = 1.0f / currentSource.height; + + if (m_TemporalStableDownsampling) + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.ThirteenTemporalCurve); + else + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.FourCurve); + filmicCurveDone = true; + } + else + { + if (m_TemporalStableDownsampling) + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.ThirteenTemporal); + else + RenderSimple(currentSource, dest, horizontalBlur * dist, verticalBlur * dist, SimpleSampleCount.Four); + } + } + + + currentSource = destinations[i]; + + } + } + + + void BrightPass(RenderTexture source, RenderTexture destination, Vector4 treshold) + { + m_BrightpassMaterial.SetTexture("_MaskTex", Texture2D.whiteTexture); + m_BrightpassMaterial.SetVector("_Threshhold", treshold); + Graphics.Blit(source, destination, m_BrightpassMaterial, 0); + } + + void BrightPassWithMask(RenderTexture source, RenderTexture destination, Vector4 treshold, Texture mask) + { + m_BrightpassMaterial.SetTexture("_MaskTex", mask); + m_BrightpassMaterial.SetVector("_Threshhold", treshold); + Graphics.Blit(source, destination, m_BrightpassMaterial, 0); + } + + void RenderSimple(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, SimpleSampleCount sampleCount) + { + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, verticalBlur, 0, 0)); + + if (sampleCount == SimpleSampleCount.Four) + Graphics.Blit(source, destination, m_SamplingMaterial, 0); + else if (sampleCount == SimpleSampleCount.Nine) + Graphics.Blit(source, destination, m_SamplingMaterial, 1); + else if (sampleCount == SimpleSampleCount.FourCurve) + Graphics.Blit(source, destination, m_SamplingMaterial, 5); + else if (sampleCount == SimpleSampleCount.ThirteenTemporal) + Graphics.Blit(source, destination, m_SamplingMaterial, 11); + else if (sampleCount == SimpleSampleCount.ThirteenTemporalCurve) + Graphics.Blit(source, destination, m_SamplingMaterial, 12); + } + + void GaussianBlur1(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity) + { + int passFromSamples = 2; + if (sampleCount == BlurSampleCount.Seventeen) + passFromSamples = 3; + if (sampleCount == BlurSampleCount.Nine) + passFromSamples = 4; + if (sampleCount == BlurSampleCount.NineCurve) + passFromSamples = 6; + if (sampleCount == BlurSampleCount.FourSimple) + passFromSamples = 7; + if (sampleCount == BlurSampleCount.Thirteen) + passFromSamples = 8; + if (sampleCount == BlurSampleCount.TwentyThree) + passFromSamples = 9; + if (sampleCount == BlurSampleCount.TwentySeven) + passFromSamples = 10; + + Texture additiveColor = null; + if (additiveTexture == null) + additiveColor = Texture2D.blackTexture; + else + additiveColor = additiveTexture; + + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, destination, m_SamplingMaterial, passFromSamples); + + } + + void GaussianBlur2(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(destination.width, destination.height, destination.depth, destination.format); + tmpTexture.filterMode = FilterMode.Bilinear; + + int passFromSamples = 2; + if (sampleCount == BlurSampleCount.Seventeen) + passFromSamples = 3; + if (sampleCount == BlurSampleCount.Nine) + passFromSamples = 4; + if (sampleCount == BlurSampleCount.NineCurve) + passFromSamples = 6; + if (sampleCount == BlurSampleCount.FourSimple) + passFromSamples = 7; + if (sampleCount == BlurSampleCount.Thirteen) + passFromSamples = 8; + if (sampleCount == BlurSampleCount.TwentyThree) + passFromSamples = 9; + if (sampleCount == BlurSampleCount.TwentySeven) + passFromSamples = 10; + + Texture additiveColor = null; + + if (additiveTexture == null) + additiveColor = Texture2D.blackTexture; + else + additiveColor = additiveTexture; + + // First pass + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, tmpTexture, m_SamplingMaterial, passFromSamples); + + additiveColor = tmpTexture; + + // Second pass + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(-horizontalBlur, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, destination, m_SamplingMaterial, passFromSamples); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + void GaussianBlurSeparate(RenderTexture source, RenderTexture destination, float horizontalBlur, float verticalBlur, RenderTexture additiveTexture, BlurSampleCount sampleCount, Color tint, float intensity) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(destination.width, destination.height, destination.depth, destination.format); + tmpTexture.filterMode = FilterMode.Bilinear; + + int passFromSamples = 2; + if (sampleCount == BlurSampleCount.Seventeen) + passFromSamples = 3; + if (sampleCount == BlurSampleCount.Nine) + passFromSamples = 4; + if (sampleCount == BlurSampleCount.NineCurve) + passFromSamples = 6; + if (sampleCount == BlurSampleCount.FourSimple) + passFromSamples = 7; + if (sampleCount == BlurSampleCount.Thirteen) + passFromSamples = 8; + if (sampleCount == BlurSampleCount.TwentyThree) + passFromSamples = 9; + if (sampleCount == BlurSampleCount.TwentySeven) + passFromSamples = 10; + + // Vertical + m_SamplingMaterial.SetTexture("_AdditiveTexture", Texture2D.blackTexture); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(0.0f, verticalBlur, 0, 0)); + m_SamplingMaterial.SetVector("_Tint", tint); + m_SamplingMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, tmpTexture, m_SamplingMaterial, passFromSamples); + + Texture additiveColor = null; + if (additiveTexture == null) + additiveColor = Texture2D.blackTexture; + else + additiveColor = additiveTexture; + + // Horizontal + m_SamplingMaterial.SetTexture("_AdditiveTexture", additiveColor); + m_SamplingMaterial.SetVector("_OffsetInfos", new Vector4(horizontalBlur, 0.0f, 1.0f / destination.width, 1.0f / destination.height)); + m_SamplingMaterial.SetVector("_Tint", Color.white); + m_SamplingMaterial.SetFloat("_Intensity", 1.0f); + Graphics.Blit(tmpTexture, destination, m_SamplingMaterial, passFromSamples); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + void RenderTextureAdditive(RenderTexture source, RenderTexture destination, float intensity) + { + + RenderTexture tmpTexture = RenderTexture.GetTemporary(source.width, source.height, source.depth, source.format); + Graphics.Blit(destination, tmpTexture); + + m_MixerMaterial.SetTexture("_ColorBuffer", tmpTexture); + m_MixerMaterial.SetFloat("_Intensity", intensity); + + Graphics.Blit(source, destination, m_MixerMaterial, 0); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + void BlitIntensity(RenderTexture source, RenderTexture destination, float intensity) + { + m_MixerMaterial.SetFloat("_Intensity", intensity); + Graphics.Blit(source, destination, m_MixerMaterial, 2); + } + + void CombineAdditive(RenderTexture source, RenderTexture destination, float intensitySource, float intensityDestination) + { + RenderTexture tmpTexture = RenderTexture.GetTemporary(source.width, source.height, source.depth, source.format); + Graphics.Blit(destination, tmpTexture); + + m_MixerMaterial.SetTexture("_ColorBuffer", tmpTexture); + m_MixerMaterial.SetFloat("_Intensity0", intensitySource); + m_MixerMaterial.SetFloat("_Intensity1", intensityDestination); + Graphics.Blit(source, destination, m_MixerMaterial, 1); + + RenderTexture.ReleaseTemporary(tmpTexture); + } + + public void SetFilmicCurveParameters(float middle, float dark, float bright, float highlights) + { + m_BloomCurve.m_ToeStrength = -1.0f * dark; + m_BloomCurve.m_ShoulderStrength = bright; + m_BloomCurve.m_Highlights = highlights; + m_BloomCurve.m_CrossOverPoint = middle; + m_BloomCurve.UpdateCoefficients(); + } + + + + /* float Gaussian(float Scale, int iSamplePoint) + { + float sigma = (Scale - 1.0f) / 6.5f; + float g = 1.0f / Mathf.Sqrt(2.0f * 3.14159f * sigma * sigma); + return (g * Mathf.Exp(-(iSamplePoint * iSamplePoint) / (2 * sigma * sigma))); + } + + void Start() + { + int count = 16; + float scale = 31; + float sum = 0.0f; + float[] weights = new float[count]; + for (int i = 0; i < count; ++i) + { + weights[i] = Gaussian(scale, i); + sum += weights[i]; + } + + string str = ""; + for (int i = 0; i < count; ++i) + { + float nWeight = weights[i] / sum; + + if (i == 0) + { + str += "color += " + nWeight + " * tex2D (_MainTex, gUV);\n"; + } + else + { + str += "color += " + nWeight + " * tex2D (_MainTex, gUV + _OffsetInfos.xy * " + i + ");\n"; + str += "color += " + nWeight + " * tex2D (_MainTex, gUV - _OffsetInfos.xy * " + i + ");\n"; + } + //Debug.Log("" + i + ": " + nWeight); + } + + Debug.Log(str); + } + * */ +} + + diff --git a/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta new file mode 100644 index 0000000..6263d1b --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/Scripts/UltimateBloom.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c248faf0e10cd5a4cb2ca648c286bfa8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs new file mode 100644 index 0000000..78719e6 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs @@ -0,0 +1,10 @@ +using UnityEngine; +using System.Collections; + +/// +/// Used to locate the root Ultimate Bloom Folder +/// +public class UltimateBloomPathLocator : ScriptableObject +{ + +} diff --git a/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta new file mode 100644 index 0000000..8c1f6b2 --- /dev/null +++ b/Assets/Cinematic Effects/BloomBeta/UltimateBloomPathLocator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f196cd8bdabf54842954784952e8d059 +timeCreated: 1456303354 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common.meta b/Assets/Cinematic Effects/Common.meta new file mode 100644 index 0000000..df0a642 --- /dev/null +++ b/Assets/Cinematic Effects/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 88d2f1c604c7f6d4bb80a72b2f0219a7 +folderAsset: yes +timeCreated: 1449044555 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor.meta b/Assets/Cinematic Effects/Common/Editor.meta new file mode 100644 index 0000000..1acf785 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e862ecde714eb154ca2d86a9a0809732 +folderAsset: yes +timeCreated: 1453372226 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs new file mode 100644 index 0000000..05fb09a --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using UnityEditor; +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + public static class EditorGUIHelper + { + private static Styles s_Styles; + private class Styles + { + public GUIStyle header = "ShurikenModuleTitle"; + public GUIStyle headerCheckbox = "ShurikenCheckMark"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + header.border = new RectOffset(15, 7, 4, 4); + header.fixedHeight = 22; + header.contentOffset = new Vector2(20f, -2f); + } + } + + static EditorGUIHelper() + { + s_Styles = new Styles(); + } + + public static bool Header(SerializedProperty group, SerializedProperty enabledField) + { + var display = group == null || group.isExpanded; + var enabled = enabledField != null && enabledField.boolValue; + var title = group == null ? "Unknown Group" : ObjectNames.NicifyVariableName(group.displayName); + + Rect rect = GUILayoutUtility.GetRect(16f, 22f, s_Styles.header); + GUI.Box(rect, title, s_Styles.header); + + Rect toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f); + if (Event.current.type == EventType.Repaint) + s_Styles.headerCheckbox.Draw(toggleRect, false, false, enabled, false); + + Event e = Event.current; + if (e.type == EventType.MouseDown) + { + if (toggleRect.Contains(e.mousePosition) && enabledField != null) + { + enabledField.boolValue = !enabledField.boolValue; + e.Use(); + } + else if (rect.Contains(e.mousePosition) && group != null) + { + display = !display; + group.isExpanded = !group.isExpanded; + e.Use(); + } + } + return display; + } + } +} diff --git a/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta new file mode 100644 index 0000000..0bb1a64 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/EditorGUIHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5b995f06a3ed14d449823cf7ab1c5a58 +timeCreated: 1454681943 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs new file mode 100644 index 0000000..fe77bdd --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + public static class FieldFinder + { + public static FieldInfo GetField(Expression> selector) + { + Expression body = selector; + if (body is LambdaExpression) + { + body = ((LambdaExpression)body).Body; + } + switch (body.NodeType) + { + case ExpressionType.MemberAccess: + return (FieldInfo)((MemberExpression)body).Member; + default: + throw new InvalidOperationException(); + } + } + } +} diff --git a/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta new file mode 100644 index 0000000..6a4c16d --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/FieldFinder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39e54cb37a3a81a40b248f1cc25c4619 +timeCreated: 1454073160 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs new file mode 100644 index 0000000..73ca7b2 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs @@ -0,0 +1,29 @@ +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomPropertyDrawer(typeof(MinAttribute))] + internal sealed class MinDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + MinAttribute attribute = (MinAttribute) base.attribute; + + if (property.propertyType == SerializedPropertyType.Integer) + { + int v = EditorGUI.IntField(position, label, property.intValue); + property.intValue = (int)Mathf.Max(v, attribute.min); + } + else if (property.propertyType == SerializedPropertyType.Float) + { + float v = EditorGUI.FloatField(position, label, property.floatValue); + property.floatValue = Mathf.Max(v, attribute.min); + } + else + { + EditorGUI.LabelField(position, label.text, "Use Min with float or int."); + } + } + } +} diff --git a/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta new file mode 100644 index 0000000..2e95f53 --- /dev/null +++ b/Assets/Cinematic Effects/Common/Editor/MinDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9c615a85f13c6764fa4496d1d7f75f52 +timeCreated: 1453220014 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/ImageEffectHelper.cs b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs new file mode 100644 index 0000000..d3761b6 --- /dev/null +++ b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs @@ -0,0 +1,63 @@ +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UnityStandardAssets.CinematicEffects +{ + public static class ImageEffectHelper + { + public static bool IsSupported(Shader s, bool needDepth, bool needHdr, MonoBehaviour effect) + { +#if UNITY_EDITOR + // Don't check for shader compatibility while it's building as it would disable most effects + // on build farms without good-enough gaming hardware. + if (!BuildPipeline.isBuildingPlayer) + { +#endif + if (s == null || !s.isSupported) + { + Debug.LogWarningFormat("Missing shader for image effect {0}", effect); + return false; + } + + if (!SystemInfo.supportsImageEffects || !SystemInfo.supportsRenderTextures) + { + Debug.LogWarningFormat("Image effects aren't supported on this device ({0})", effect); + return false; + } + + if (needDepth && !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth)) + { + Debug.LogWarningFormat("Depth textures aren't supported on this device ({0})", effect); + return false; + } + + if (needHdr && !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)) + { + Debug.LogWarningFormat("Floating point textures aren't supported on this device ({0})", effect); + return false; + } +#if UNITY_EDITOR + } +#endif + + return true; + } + + public static Material CheckShaderAndCreateMaterial(Shader s) + { + if (s == null || !s.isSupported) + return null; + + var material = new Material(s); + material.hideFlags = HideFlags.DontSave; + return material; + } + + public static bool supportsDX11 + { + get { return SystemInfo.graphicsShaderLevel >= 50 && SystemInfo.supportsComputeShaders; } + } + } +} diff --git a/Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta new file mode 100644 index 0000000..eb58b71 --- /dev/null +++ b/Assets/Cinematic Effects/Common/ImageEffectHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ab6a3f50deeee984c88794eeeb901226 +timeCreated: 1448544124 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/MinAttribute.cs b/Assets/Cinematic Effects/Common/MinAttribute.cs new file mode 100644 index 0000000..84e7c1a --- /dev/null +++ b/Assets/Cinematic Effects/Common/MinAttribute.cs @@ -0,0 +1,14 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + + public sealed class MinAttribute : PropertyAttribute + { + public readonly float min; + + public MinAttribute(float min) + { + this.min = min; + } + } +} diff --git a/Assets/Cinematic Effects/Common/MinAttribute.cs.meta b/Assets/Cinematic Effects/Common/MinAttribute.cs.meta new file mode 100644 index 0000000..8dcc710 --- /dev/null +++ b/Assets/Cinematic Effects/Common/MinAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b07292ae638766047a6751da7552e566 +timeCreated: 1453220005 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/Common/RenderTextureUtility.cs b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs new file mode 100644 index 0000000..ae71657 --- /dev/null +++ b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public class RenderTextureUtility + { + //Temporary render texture handling + private List m_TemporaryRTs = new List(); + + public RenderTexture GetTemporaryRenderTexture(int width, int height, int depthBuffer = 0, RenderTextureFormat format = RenderTextureFormat.ARGBHalf, FilterMode filterMode = FilterMode.Bilinear) + { + var rt = RenderTexture.GetTemporary(width, height, depthBuffer, format); + rt.filterMode = filterMode; + rt.wrapMode = TextureWrapMode.Clamp; + rt.name = "RenderTextureUtilityTempTexture"; + m_TemporaryRTs.Add(rt); + return rt; + } + + public void ReleaseTemporaryRenderTexture(RenderTexture rt) + { + if (rt == null) + return; + + if (!m_TemporaryRTs.Contains(rt)) + { + Debug.LogErrorFormat("Attempting to remove texture that was not allocated: {0}", rt); + return; + } + + m_TemporaryRTs.Remove(rt); + RenderTexture.ReleaseTemporary(rt); + } + + public void ReleaseAllTemporaryRenderTextures() + { + for (int i = 0; i < m_TemporaryRTs.Count; ++i) + RenderTexture.ReleaseTemporary(m_TemporaryRTs[i]); + + m_TemporaryRTs.Clear(); + } + } +} diff --git a/Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta new file mode 100644 index 0000000..b866db1 --- /dev/null +++ b/Assets/Cinematic Effects/Common/RenderTextureUtility.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 054e694bae00c374a97c2bc495fca66b +timeCreated: 1449148391 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField.meta b/Assets/Cinematic Effects/DepthOfField.meta new file mode 100644 index 0000000..50072ec --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 34369cdf66de04c65a8cef766bb1797b +folderAsset: yes +timeCreated: 1429220270 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs new file mode 100644 index 0000000..ec469ec --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs @@ -0,0 +1,946 @@ +using UnityEngine; +using System; + +namespace UnityStandardAssets.CinematicEffects +{ + //Improvement ideas: + // Use rgba8 buffer in ldr / in some pass in hdr (in correlation to previous point and remapping coc from -1/0/1 to 0/0.5/1) + // Use temporal stabilisation. + // Add a mode to do bokeh texture in quarter res as well + // Support different near and far blur for the bokeh texture + // Try distance field for the bokeh texture. + // Try to separate the output of the blur pass to two rendertarget near+far, see the gain in quality vs loss in performance. + // Try swirl effect on the samples of the circle blur. + + //References : + // This DOF implementation use ideas from public sources, a big thank to them : + // http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare + // http://www.crytek.com/download/Sousa_Graphics_Gems_CryENGINE3.pdf + // http://graphics.cs.williams.edu/papers/MedianShaderX6/ + // http://http.developer.nvidia.com/GPUGems/gpugems_ch24.html + // http://vec3.ca/bicubic-filtering-in-fewer-taps/ + + [ExecuteInEditMode] + [AddComponentMenu("Image Effects/Cinematic/Depth Of Field")] + [RequireComponent(typeof(Camera))] + public class DepthOfField : MonoBehaviour + { + private const float kMaxBlur = 35.0f; + + #region Render passes + private enum Passes + { + BlurAlphaWeighted = 0 , + BoxBlur = 1 , + DilateFgCocFromColor = 2 , + DilateFgCoc = 3 , + CaptureCoc = 4 , + CaptureCocExplicit = 5 , + VisualizeCoc = 6 , + VisualizeCocExplicit = 7 , + CocPrefilter = 8 , + CircleBlur = 9 , + CircleBlurWithDilatedFg = 10, + CircleBlurLowQuality = 11, + CircleBlowLowQualityWithDilatedFg = 12, + Merge = 13, + MergeExplicit = 14, + MergeBicubic = 15, + MergeExplicitBicubic = 16, + ShapeLowQuality = 17, + ShapeLowQualityDilateFg = 18, + ShapeLowQualityMerge = 19, + ShapeLowQualityMergeDilateFg = 20, + ShapeMediumQuality = 21, + ShapeMediumQualityDilateFg = 22, + ShapeMediumQualityMerge = 23, + ShapeMediumQualityMergeDilateFg = 24, + ShapeHighQuality = 25, + ShapeHighQualityDilateFg = 26, + ShapeHighQualityMerge = 27, + ShapeHighQualityMergeDilateFg = 28 + } + + private enum MedianPasses + { + Median3 = 0, + Median3X3 = 1 + } + + private enum BokehTexturesPasses + { + Apply = 0, + Collect = 1 + } + #endregion + + public enum TweakMode + { + Basic, + Advanced, + Explicit + } + + public enum ApertureShape + { + Circular, + Hexagonal, + Octogonal + } + + public enum QualityPreset + { + Simple, + Low, + Medium, + High, + VeryHigh, + Ultra, + Custom + } + + public enum FilterQuality + { + None, + Normal, + High + } + + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class TopLevelSettings : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class AllTweakModes : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class Basic : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class Advanced : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class Explicit : Attribute + {} + #endregion + + #region Settings + [Serializable] + public struct GlobalSettings + { + [Tooltip("Allows to view where the blur will be applied. Yellow for near blur, blue for far blur.")] + public bool visualizeBluriness; + + [Tooltip("Setup mode. Use \"Advanced\" if you need more control on blur settings and/or want to use a bokeh texture. \"Explicit\" is the same as \"Advanced\" but makes use of \"Near Plane\" and \"Far Plane\" values instead of \"F-Stop\".")] + public TweakMode tweakMode; + + [Tooltip("Quality presets. Use \"Custom\" for more advanced settings.")] + public QualityPreset quality; + + [Space, Tooltip("\"Circular\" is the fastest, followed by \"Hexagonal\" and \"Octogonal\".")] + public ApertureShape apertureShape; + + [Range(0f, 179f), Tooltip("Rotates the aperture when working with \"Hexagonal\" and \"Ortogonal\".")] + public float apertureOrientation; + + public static GlobalSettings defaultSettings + { + get + { + return new GlobalSettings + { + visualizeBluriness = false, + tweakMode = TweakMode.Basic, + quality = QualityPreset.High, + apertureShape = ApertureShape.Circular, + apertureOrientation = 0f + }; + } + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("Enable this to get smooth bokeh.")] + public bool prefilterBlur; + + [Tooltip("Applies a median filter for even smoother bokeh.")] + public FilterQuality medianFilter; + + [Tooltip("Dilates near blur over in focus area.")] + public bool dilateNearBlur; + + [Tooltip("Uses high quality upsampling.")] + public bool highQualityUpsampling; + + [Tooltip("Prevent haloing from bright in focus region over dark out of focus region.")] + public bool preventHaloing; + + public static QualitySettings[] presetQualitySettings = + { + // Simple + new QualitySettings + { + prefilterBlur = false, + medianFilter = FilterQuality.None, + dilateNearBlur = false, + highQualityUpsampling = false, + preventHaloing = false + }, + + // Low + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.None, + dilateNearBlur = false, + highQualityUpsampling = false, + preventHaloing = false + }, + + // Medium + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.Normal, + dilateNearBlur = false, + highQualityUpsampling = false, + preventHaloing = false + }, + + // High + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.Normal, + dilateNearBlur = true, + highQualityUpsampling = false, + preventHaloing = false + }, + + // Very high + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.High, + dilateNearBlur = true, + highQualityUpsampling = false, + preventHaloing = true + }, + + // Ultra + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.High, + dilateNearBlur = true, + highQualityUpsampling = true, + preventHaloing = true + } + }; + } + + [Serializable] + public struct FocusSettings + { + [Basic, Advanced, Explicit, Tooltip("Auto-focus on a selected transform.")] + public Transform transform; + + [Basic, Advanced, Explicit, Range(0f, 1f), Tooltip("Focus distance.")] + public float plane; + + [Explicit, Range(0f, 1f), Tooltip("Near focus distance.")] + public float nearPlane; + + [Explicit, Range(0f, 1f), Tooltip("Far focus distance.")] + public float farPlane; + + [Basic, Advanced, Range(0f, 32f), Tooltip("Simulates focal ratio. Lower values will result in a narrow depth of field.")] + public float fStops; + + [Basic, Advanced, Explicit, Range(0f, 1f), Tooltip("Focus range/spread. Use this to fine-tune the F-Stop range.")] + public float rangeAdjustment; + + public static FocusSettings defaultSettings + { + get + { + return new FocusSettings + { + transform = null, + plane = 0.225f, + nearPlane = 0f, + farPlane = 1f, + fStops = 5f, + rangeAdjustment = 0.9f + }; + } + } + } + + [Serializable] + public struct BokehTextureSettings + { + [Advanced, Explicit, Tooltip("Adding a texture to this field will enable the use of \"Bokeh Textures\". Use with care. This feature is only available on Shader Model 5 compatible-hardware and performance scale with the amount of bokeh.")] + public Texture2D texture; + + [Advanced, Explicit, Range(0.01f, 5f), Tooltip("Maximum size of bokeh textures on screen.")] + public float scale; + + [Advanced, Explicit, Range(0.01f, 100f), Tooltip("Bokeh brightness.")] + public float intensity; + + [Advanced, Explicit, Range(0.01f, 50f), Tooltip("Controls the amount of bokeh textures. Lower values mean more bokeh splats.")] + public float threshold; + + [Advanced, Explicit, Range(0.01f, 1f), Tooltip("Controls the spawn conditions. Lower values mean more visible bokeh.")] + public float spawnHeuristic; + + public static BokehTextureSettings defaultSettings + { + get + { + return new BokehTextureSettings + { + texture = null, + scale = 1f, + intensity = 50f, + threshold = 2f, + spawnHeuristic = 0.15f + }; + } + } + } + + [Serializable] + public struct BlurSettings + { + [Basic, Advanced, Explicit, Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the near plane.")] + public float nearRadius; + + [Basic, Advanced, Explicit, Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the far plane.")] + public float farRadius; + + [Advanced, Explicit, Range(0.5f, 4f), Tooltip("Blur luminosity booster threshold for the near and far boost amounts.")] + public float boostPoint; + + [Advanced, Explicit, Range(0f, 1f), Tooltip("Boosts luminosity in the near blur.")] + public float nearBoostAmount; + + [Advanced, Explicit, Range(0f, 1f), Tooltip("Boosts luminosity in the far blur.")] + public float farBoostAmount; + + public static BlurSettings defaultSettings + { + get + { + return new BlurSettings + { + nearRadius = 20f, + farRadius = 20f, + boostPoint = 0.75f, + nearBoostAmount = 0f, + farBoostAmount = 0f, + }; + } + } + } + #endregion + + [TopLevelSettings] + public GlobalSettings settings = GlobalSettings.defaultSettings; + + [SettingsGroup, AllTweakModes] + public QualitySettings quality = QualitySettings.presetQualitySettings[3]; + + [SettingsGroup] + public FocusSettings focus = FocusSettings.defaultSettings; + + [SettingsGroup] + public BokehTextureSettings bokehTexture = BokehTextureSettings.defaultSettings; + + [SettingsGroup] + public BlurSettings blur = BlurSettings.defaultSettings; + + [SerializeField] + private Shader m_FilmicDepthOfFieldShader; + + public Shader filmicDepthOfFieldShader + { + get + { + if (m_FilmicDepthOfFieldShader == null) + m_FilmicDepthOfFieldShader = Shader.Find("Hidden/DepthOfField/DepthOfField"); + + return m_FilmicDepthOfFieldShader; + } + } + + [SerializeField] + private Shader m_MedianFilterShader; + + public Shader medianFilterShader + { + get + { + if (m_MedianFilterShader == null) + m_MedianFilterShader = Shader.Find("Hidden/DepthOfField/MedianFilter"); + + return m_MedianFilterShader; + } + } + + [SerializeField] + private Shader m_TextureBokehShader; + + public Shader textureBokehShader + { + get + { + if (m_TextureBokehShader == null) + m_TextureBokehShader = Shader.Find("Hidden/DepthOfField/BokehSplatting"); + + return m_TextureBokehShader; + } + } + + private RenderTextureUtility m_RTU = new RenderTextureUtility(); + + private Material m_FilmicDepthOfFieldMaterial; + + public Material filmicDepthOfFieldMaterial + { + get + { + if (m_FilmicDepthOfFieldMaterial == null) + m_FilmicDepthOfFieldMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(filmicDepthOfFieldShader); + + return m_FilmicDepthOfFieldMaterial; + } + } + + private Material m_MedianFilterMaterial; + + public Material medianFilterMaterial + { + get + { + if (m_MedianFilterMaterial == null) + m_MedianFilterMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(medianFilterShader); + + return m_MedianFilterMaterial; + } + } + + private Material m_TextureBokehMaterial; + + public Material textureBokehMaterial + { + get + { + if (m_TextureBokehMaterial == null) + m_TextureBokehMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(textureBokehShader); + + return m_TextureBokehMaterial; + } + } + + private ComputeBuffer m_ComputeBufferDrawArgs; + + public ComputeBuffer computeBufferDrawArgs + { + get + { + if (m_ComputeBufferDrawArgs == null) + { +#if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3) + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.DrawIndirect); +#else + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.IndirectArguments); +#endif + m_ComputeBufferDrawArgs.SetData(new[] {0, 1, 0, 0}); + } + + return m_ComputeBufferDrawArgs; + } + } + + private ComputeBuffer m_ComputeBufferPoints; + + public ComputeBuffer computeBufferPoints + { + get + { + if (m_ComputeBufferPoints == null) + m_ComputeBufferPoints = new ComputeBuffer(90000, 12 + 16, ComputeBufferType.Append); + + return m_ComputeBufferPoints; + } + } + + private QualitySettings m_CurrentQualitySettings; + private float m_LastApertureOrientation; + private Vector4 m_OctogonalBokehDirection1; + private Vector4 m_OctogonalBokehDirection2; + private Vector4 m_OctogonalBokehDirection3; + private Vector4 m_OctogonalBokehDirection4; + private Vector4 m_HexagonalBokehDirection1; + private Vector4 m_HexagonalBokehDirection2; + private Vector4 m_HexagonalBokehDirection3; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(filmicDepthOfFieldShader, true, true, this) || !ImageEffectHelper.IsSupported(medianFilterShader, true, true, this)) + { + enabled = false; + return; + } + + if (ImageEffectHelper.supportsDX11 && !ImageEffectHelper.IsSupported(textureBokehShader, true, true, this)) + { + enabled = false; + return; + } + + ComputeBlurDirections(true); + GetComponent().depthTextureMode |= DepthTextureMode.Depth; + } + + private void OnDisable() + { + ReleaseComputeResources(); + + if (m_FilmicDepthOfFieldMaterial != null) + DestroyImmediate(m_FilmicDepthOfFieldMaterial); + + if (m_TextureBokehMaterial != null) + DestroyImmediate(m_TextureBokehMaterial); + + if (m_MedianFilterMaterial != null) + DestroyImmediate(m_MedianFilterMaterial); + + m_FilmicDepthOfFieldMaterial = null; + m_TextureBokehMaterial = null; + m_MedianFilterMaterial = null; + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + //-------------------------------------------------------------------// + // Main entry point // + //-------------------------------------------------------------------// + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (medianFilterMaterial == null || filmicDepthOfFieldMaterial == null) + { + Graphics.Blit(source, destination); + return; + } + + if (settings.visualizeBluriness) + { + Vector4 blurrinessParam; + Vector4 blurrinessCoe; + ComputeCocParameters(out blurrinessParam, out blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", blurrinessParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + Graphics.Blit(null, destination, filmicDepthOfFieldMaterial, (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.VisualizeCocExplicit : (int)Passes.VisualizeCoc); + } + else + { + DoDepthOfField(source, destination); + } + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + private void DoDepthOfField(RenderTexture source, RenderTexture destination) + { + m_CurrentQualitySettings = quality; + + if (settings.quality != QualityPreset.Custom) + m_CurrentQualitySettings = QualitySettings.presetQualitySettings[(int)settings.quality]; + + float radiusAdjustement = source.height / 720.0f; + + float textureBokehScale = radiusAdjustement; + float textureBokehMaxRadius = Mathf.Max(blur.nearRadius, blur.farRadius) * textureBokehScale * 0.75f; + + float nearBlurRadius = blur.nearRadius * radiusAdjustement; + float farBlurRadius = blur.farRadius * radiusAdjustement; + float maxBlurRadius = Mathf.Max(nearBlurRadius, farBlurRadius); + switch (settings.apertureShape) + { + case ApertureShape.Hexagonal: + maxBlurRadius *= 1.2f; + break; + case ApertureShape.Octogonal: + maxBlurRadius *= 1.15f; + break; + } + + if (maxBlurRadius < 0.5f) + { + Graphics.Blit(source, destination); + return; + } + + // Quarter resolution + int rtW = source.width / 2; + int rtH = source.height / 2; + Vector4 blurrinessCoe = new Vector4(nearBlurRadius * 0.5f, farBlurRadius * 0.5f, 0.0f, 0.0f); + RenderTexture colorAndCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + RenderTexture colorAndCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + + if (m_CurrentQualitySettings.preventHaloing) + filmicDepthOfFieldMaterial.EnableKeyword("USE_SPECIAL_FETCH_FOR_COC"); + else + filmicDepthOfFieldMaterial.DisableKeyword("USE_SPECIAL_FETCH_FOR_COC"); + + // Downsample to Color + COC buffer and apply boost + Vector4 cocParam; + Vector4 cocCoe; + ComputeCocParameters(out cocParam, out cocCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", cocCoe); + filmicDepthOfFieldMaterial.SetVector("_BoostParams", new Vector4(nearBlurRadius * blur.nearBoostAmount * -0.5f, farBlurRadius * blur.farBoostAmount * 0.5f, blur.boostPoint, 0.0f)); + Graphics.Blit(source, colorAndCoc2, filmicDepthOfFieldMaterial, (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.CaptureCocExplicit : (int)Passes.CaptureCoc); + RenderTexture src = colorAndCoc2; + RenderTexture dst = colorAndCoc; + + // Collect texture bokeh candidates and replace with a darker pixel + if (shouldPerformBokeh) + { + // Blur a bit so we can do a frequency check + RenderTexture blurred = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + Graphics.Blit(src, blurred, filmicDepthOfFieldMaterial, (int)Passes.BoxBlur); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0.0f, 1.5f, 0.0f, 1.5f)); + Graphics.Blit(blurred, dst, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(1.5f, 0.0f, 0.0f, 1.5f)); + Graphics.Blit(dst, blurred, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + + // Collect texture bokeh candidates and replace with a darker pixel + textureBokehMaterial.SetTexture("_BlurredColor", blurred); + textureBokehMaterial.SetFloat("_SpawnHeuristic", bokehTexture.spawnHeuristic); + textureBokehMaterial.SetVector("_BokehParams", new Vector4(bokehTexture.scale * textureBokehScale, bokehTexture.intensity, bokehTexture.threshold, textureBokehMaxRadius)); + Graphics.SetRandomWriteTarget(1, computeBufferPoints); + Graphics.Blit(src, dst, textureBokehMaterial, (int)BokehTexturesPasses.Collect); + Graphics.ClearRandomWriteTargets(); + SwapRenderTexture(ref src, ref dst); + m_RTU.ReleaseTemporaryRenderTexture(blurred); + } + + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_BoostParams", new Vector4(nearBlurRadius * blur.nearBoostAmount * -0.5f, farBlurRadius * blur.farBoostAmount * 0.5f, blur.boostPoint, 0.0f)); + + // Dilate near blur factor + RenderTexture blurredFgCoc = null; + if (m_CurrentQualitySettings.dilateNearBlur) + { + RenderTexture blurredFgCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + blurredFgCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0.0f, nearBlurRadius * 0.75f, 0.0f, 0.0f)); + Graphics.Blit(src, blurredFgCoc2, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCocFromColor); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(nearBlurRadius * 0.75f, 0.0f, 0.0f, 0.0f)); + Graphics.Blit(blurredFgCoc2, blurredFgCoc, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCoc); + m_RTU.ReleaseTemporaryRenderTexture(blurredFgCoc2); + blurredFgCoc.filterMode = FilterMode.Point; + } + + // Blur downsampled color to fill the gap between samples + if (m_CurrentQualitySettings.prefilterBlur) + { + Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, (int)Passes.CocPrefilter); + SwapRenderTexture(ref src, ref dst); + } + + // Apply blur : Circle / Hexagonal or Octagonal (blur will create bokeh if bright pixel where not removed by "m_UseBokehTexture") + switch (settings.apertureShape) + { + case ApertureShape.Circular: + DoCircularBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + case ApertureShape.Hexagonal: + DoHexagonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + case ApertureShape.Octogonal: + DoOctogonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + } + + // Smooth result + switch (m_CurrentQualitySettings.medianFilter) + { + case FilterQuality.Normal: + { + medianFilterMaterial.SetVector("_Offsets", new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + medianFilterMaterial.SetVector("_Offsets", new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + break; + } + case FilterQuality.High: + { + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3X3); + SwapRenderTexture(ref src, ref dst); + break; + } + } + + // Merge to full resolution (with boost) + upsampling (linear or bicubic) + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_Convolved_TexelSize", new Vector4(src.width, src.height, 1.0f / src.width, 1.0f / src.height)); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", src); + int mergePass = (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.MergeExplicit : (int)Passes.Merge; + if (m_CurrentQualitySettings.highQualityUpsampling) + mergePass = (settings.tweakMode == TweakMode.Explicit) ? (int)Passes.MergeExplicitBicubic : (int)Passes.MergeBicubic; + + // Apply texture bokeh + if (shouldPerformBokeh) + { + RenderTexture tmp = m_RTU.GetTemporaryRenderTexture(source.height, source.width, 0, source.format); + Graphics.Blit(source, tmp, filmicDepthOfFieldMaterial, mergePass); + + Graphics.SetRenderTarget(tmp); + ComputeBuffer.CopyCount(computeBufferPoints, computeBufferDrawArgs, 0); + textureBokehMaterial.SetBuffer("pointBuffer", computeBufferPoints); + textureBokehMaterial.SetTexture("_MainTex", bokehTexture.texture); + textureBokehMaterial.SetVector("_Screen", new Vector3(1.0f / (1.0f * source.width), 1.0f / (1.0f * source.height), textureBokehMaxRadius)); + textureBokehMaterial.SetPass((int)BokehTexturesPasses.Apply); + Graphics.DrawProceduralIndirect(MeshTopology.Points, computeBufferDrawArgs, 0); + Graphics.Blit(tmp, destination); // hackaround for DX11 flipfun (OPTIMIZEME) + } + else + { + Graphics.Blit(source, destination, filmicDepthOfFieldMaterial, mergePass); + } + } + + //-------------------------------------------------------------------// + // Blurs // + //-------------------------------------------------------------------// + private void DoHexagonalBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + ComputeBlurDirections(false); + + int blurPass; + int blurPassMerge; + GetDirectionalBlurPassesFromRadius(blurredFgCoc, maxRadius, out blurPass, out blurPassMerge); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + RenderTexture tmp = m_RTU.GetTemporaryRenderTexture(src.width, src.height, 0, src.format); + + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection1); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection2); + Graphics.Blit(tmp, src, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection3); + filmicDepthOfFieldMaterial.SetTexture("_ThirdTex", src); + Graphics.Blit(tmp, dst, filmicDepthOfFieldMaterial, blurPassMerge); + m_RTU.ReleaseTemporaryRenderTexture(tmp); + SwapRenderTexture(ref src, ref dst); + } + + private void DoOctogonalBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + ComputeBlurDirections(false); + + int blurPass; + int blurPassMerge; + GetDirectionalBlurPassesFromRadius(blurredFgCoc, maxRadius, out blurPass, out blurPassMerge); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + RenderTexture tmp = m_RTU.GetTemporaryRenderTexture(src.width, src.height, 0, src.format); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection1); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection2); + Graphics.Blit(tmp, dst, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection3); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection4); + filmicDepthOfFieldMaterial.SetTexture("_ThirdTex", dst); + Graphics.Blit(tmp, src, filmicDepthOfFieldMaterial, blurPassMerge); + m_RTU.ReleaseTemporaryRenderTexture(tmp); + } + + private void DoCircularBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + int bokehPass; + if (blurredFgCoc != null) + { + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + bokehPass = (maxRadius > 10.0f) ? (int)Passes.CircleBlurWithDilatedFg : (int)Passes.CircleBlowLowQualityWithDilatedFg; + } + else + { + bokehPass = (maxRadius > 10.0f) ? (int)Passes.CircleBlur : (int)Passes.CircleBlurLowQuality; + } + Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, bokehPass); + SwapRenderTexture(ref src, ref dst); + } + + //-------------------------------------------------------------------// + // Helpers // + //-------------------------------------------------------------------// + private void ComputeCocParameters(out Vector4 blurParams, out Vector4 blurCoe) + { + Camera sceneCamera = GetComponent(); + float focusDistance01 = focus.transform + ? (sceneCamera.WorldToViewportPoint(focus.transform.position)).z / (sceneCamera.farClipPlane) + : (focus.plane * focus.plane * focus.plane * focus.plane); + + if (settings.tweakMode == TweakMode.Basic || settings.tweakMode == TweakMode.Advanced) + { + float focusRange01 = focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment; + float focalLength = 4.0f / Mathf.Tan(0.5f * sceneCamera.fieldOfView * Mathf.Deg2Rad); + float aperture = focalLength / focus.fStops; + blurCoe = new Vector4(0.0f, 0.0f, 1.0f, 1.0f); + blurParams = new Vector4(aperture, focalLength, focusDistance01, focusRange01); + } + else + { + float nearDistance01 = focus.nearPlane * focus.nearPlane * focus.nearPlane * focus.nearPlane; + float farDistance01 = focus.farPlane * focus.farPlane * focus.farPlane * focus.farPlane; + float nearFocusRange01 = focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment * focus.rangeAdjustment; + float farFocusRange01 = nearFocusRange01; + + if (focusDistance01 <= nearDistance01) + focusDistance01 = nearDistance01 + 0.0000001f; + if (focusDistance01 >= farDistance01) + focusDistance01 = farDistance01 - 0.0000001f; + if ((focusDistance01 - nearFocusRange01) <= nearDistance01) + nearFocusRange01 = (focusDistance01 - nearDistance01 - 0.0000001f); + if ((focusDistance01 + farFocusRange01) >= farDistance01) + farFocusRange01 = (farDistance01 - focusDistance01 - 0.0000001f); + + float a1 = 1.0f / (nearDistance01 - focusDistance01 + nearFocusRange01); + float a2 = 1.0f / (farDistance01 - focusDistance01 - farFocusRange01); + float b1 = (1.0f - a1 * nearDistance01), b2 = (1.0f - a2 * farDistance01); + const float c1 = -1.0f; + const float c2 = 1.0f; + blurParams = new Vector4(c1 * a1, c1 * b1, c2 * a2, c2 * b2); + blurCoe = new Vector4(0.0f, 0.0f, (b2 - b1) / (a1 - a2), 0.0f); + } + } + + private void ReleaseComputeResources() + { + if (m_ComputeBufferDrawArgs != null) + m_ComputeBufferDrawArgs.Release(); + + if (m_ComputeBufferPoints != null) + m_ComputeBufferPoints.Release(); + + m_ComputeBufferDrawArgs = null; + m_ComputeBufferPoints = null; + } + + private void ComputeBlurDirections(bool force) + { + if (!force && Math.Abs(m_LastApertureOrientation - settings.apertureOrientation) < float.Epsilon) + return; + + m_LastApertureOrientation = settings.apertureOrientation; + + float rotationRadian = settings.apertureOrientation * Mathf.Deg2Rad; + float cosinus = Mathf.Cos(rotationRadian); + float sinus = Mathf.Sin(rotationRadian); + + m_OctogonalBokehDirection1 = new Vector4(0.5f, 0.0f, 0.0f, 0.0f); + m_OctogonalBokehDirection2 = new Vector4(0.0f, 0.5f, 1.0f, 0.0f); + m_OctogonalBokehDirection3 = new Vector4(-0.353553f, 0.353553f, 1.0f, 0.0f); + m_OctogonalBokehDirection4 = new Vector4(0.353553f, 0.353553f, 1.0f, 0.0f); + + m_HexagonalBokehDirection1 = new Vector4(0.5f, 0.0f, 0.0f, 0.0f); + m_HexagonalBokehDirection2 = new Vector4(0.25f, 0.433013f, 1.0f, 0.0f); + m_HexagonalBokehDirection3 = new Vector4(0.25f, -0.433013f, 1.0f, 0.0f); + + if (rotationRadian > float.Epsilon) + { + Rotate2D(ref m_OctogonalBokehDirection1, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection2, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection3, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection4, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection1, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection2, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection3, cosinus, sinus); + } + } + + private bool shouldPerformBokeh + { + get { return ImageEffectHelper.supportsDX11 && bokehTexture.texture != null && textureBokehMaterial && settings.tweakMode != TweakMode.Basic; } + } + + private static void Rotate2D(ref Vector4 direction, float cosinus, float sinus) + { + Vector4 source = direction; + direction.x = source.x * cosinus - source.y * sinus; + direction.y = source.x * sinus + source.y * cosinus; + } + + private static void SwapRenderTexture(ref RenderTexture src, ref RenderTexture dst) + { + RenderTexture tmp = dst; + dst = src; + src = tmp; + } + + private static void GetDirectionalBlurPassesFromRadius(RenderTexture blurredFgCoc, float maxRadius, out int blurPass, out int blurAndMergePass) + { + if (blurredFgCoc == null) + { + if (maxRadius > 10.0f) + { + blurPass = (int)Passes.ShapeHighQuality; + blurAndMergePass = (int)Passes.ShapeHighQualityMerge; + } + else if (maxRadius > 5.0f) + { + blurPass = (int)Passes.ShapeMediumQuality; + blurAndMergePass = (int)Passes.ShapeMediumQualityMerge; + } + else + { + blurPass = (int)Passes.ShapeLowQuality; + blurAndMergePass = (int)Passes.ShapeLowQualityMerge; + } + } + else + { + if (maxRadius > 10.0f) + { + blurPass = (int)Passes.ShapeHighQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeHighQualityMergeDilateFg; + } + else if (maxRadius > 5.0f) + { + blurPass = (int)Passes.ShapeMediumQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeMediumQualityMergeDilateFg; + } + else + { + blurPass = (int)Passes.ShapeLowQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeLowQualityMergeDilateFg; + } + } + } + } +} diff --git a/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta new file mode 100644 index 0000000..9216b06 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/DepthOfField.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a338d679868f45439ea43c7ae035e36 +timeCreated: 1453985420 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_FilmicDepthOfFieldShader: {fileID: 4800000, guid: bff0e5458fb914f5c9985ba4f09171d2, + type: 3} + - m_MedianFilterShader: {fileID: 4800000, guid: a058b22d4123add4b807e832604e5e7b, + type: 3} + - m_TextureBokehShader: {fileID: 4800000, guid: c961b8ed1f00f924d804ada5143bd0e8, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Editor.meta b/Assets/Cinematic Effects/DepthOfField/Editor.meta new file mode 100644 index 0000000..e10867b --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1a8273952ce5743428d8c42b25cb0458 +folderAsset: yes +timeCreated: 1449046242 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs new file mode 100644 index 0000000..9c35a4d --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs @@ -0,0 +1,109 @@ +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomEditor(typeof(DepthOfField))] + class DepthOfFieldEditor : Editor + { + private List m_TopLevelFields = new List(); + private Dictionary> m_GroupFields = new Dictionary>(); + private Dictionary> m_AccessFields = new Dictionary>(); + + private DepthOfField.TweakMode tweakMode + { + get { return ((DepthOfField)target).settings.tweakMode; } + } + + private void OnEnable() + { + var topLevelSettings = typeof(DepthOfField).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(DepthOfField.TopLevelSettings), false).Any()); + var settingsGroups = typeof(DepthOfField).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(DepthOfField.SettingsGroup), false).Any()); + + foreach (var group in topLevelSettings) + { + var searchPath = group.Name + "."; + + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + m_TopLevelFields.Add(property); + } + } + + var basicFields = new List(); + var advancedFields = new List(); + var explicitFields = new List(); + + foreach (var group in settingsGroups) + { + var searchPath = group.Name + "."; + + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + { + settingsGroup.Add(property); + if (setting.GetCustomAttributes(typeof(DepthOfField.Basic), false).Length > 0) + basicFields.Add(property); + if (setting.GetCustomAttributes(typeof(DepthOfField.Advanced), false).Length > 0) + advancedFields.Add(property); + if (setting.GetCustomAttributes(typeof(DepthOfField.Explicit), false).Length > 0) + explicitFields.Add(property); + } + } + } + + m_AccessFields[DepthOfField.TweakMode.Basic] = basicFields; + m_AccessFields[DepthOfField.TweakMode.Advanced] = advancedFields; + m_AccessFields[DepthOfField.TweakMode.Explicit] = explicitFields; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + foreach (var setting in m_TopLevelFields) + EditorGUILayout.PropertyField(setting); + + List accessList = m_AccessFields[tweakMode]; + + foreach (var group in m_GroupFields) + { + if (group.Key.FieldType == typeof(DepthOfField.QualitySettings) && ((DepthOfField)target).settings.quality != DepthOfField.QualityPreset.Custom) + continue; + + bool forceInclude = group.Key.GetCustomAttributes(typeof(DepthOfField.AllTweakModes), false).Length > 0; + + int count = group.Value.Count(x => accessList.Contains(x)); + if (!forceInclude && count == 0) + continue; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField(ObjectNames.NicifyVariableName(group.Key.Name), EditorStyles.boldLabel); + EditorGUI.indentLevel++; + + foreach (var field in group.Value) + { + if (forceInclude || accessList.Contains(field)) + EditorGUILayout.PropertyField(field); + } + + EditorGUI.indentLevel--; + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta new file mode 100644 index 0000000..5ccd63d --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3eb07ef5681934662814cc768bcdb60c +timeCreated: 1429220270 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers.meta b/Assets/Cinematic Effects/DepthOfField/Helpers.meta new file mode 100644 index 0000000..59bf0ab --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5427d9a5126366c42b9509de8233bff7 +folderAsset: yes +timeCreated: 1453985653 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd b/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd new file mode 100644 index 0000000..eef48cb Binary files /dev/null and b/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd differ diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta b/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta new file mode 100644 index 0000000..213b2ae --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers/HexShape.psd.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: 904882c15ff3d4122a99f80ff4f23741 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif b/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif new file mode 100644 index 0000000..9dccaf3 Binary files /dev/null and b/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif differ diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta b/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta new file mode 100644 index 0000000..ce68835 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 9014ef007a9a1d545b0fba20daa0fc7c +timeCreated: 1454425451 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 1 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd b/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd new file mode 100644 index 0000000..a100649 Binary files /dev/null and b/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd differ diff --git a/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd.meta b/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd.meta new file mode 100644 index 0000000..e3d39b0 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Helpers/SphereShape.psd.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: 5a26d04dc2c4a407b97a20b893e69203 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Resources.meta b/Assets/Cinematic Effects/DepthOfField/Resources.meta new file mode 100644 index 0000000..c9a9d2f --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: aa2234edaeebe8b4fb5d67be342dbac9 +folderAsset: yes +timeCreated: 1453906992 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader b/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader new file mode 100644 index 0000000..341c9c0 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader @@ -0,0 +1,227 @@ + +/* + DX11 Bokeh splatting + + basic algorithm: + * find bright spots + * verify high frequency (otherwise dont care) + * if possitive, replace with black pixel and add to append buffer + * blend bokeh texture sprites via append buffer on top of blurred buffer +*/ + +Shader "Hidden/DepthOfField/BokehSplatting" +{ + Properties + { + _MainTex ("", 2D) = "white" {} + _BlurredColor ("", 2D) = "white" {} + _FgCocMask ("", 2D) = "white" {} + } + + CGINCLUDE + + #include "UnityCG.cginc" + + #define BOKEH_ZERO_VEC (float4(0,0,0,0)) + #define BOKEH_ONE_VEC (float4(1,1,1,1)) + + float4 _BokehParams; // legend: dx11BokehScale, dx11BokehIntensity,dx11BokehThreshhold, internalBlurWidth + float4 _MainTex_TexelSize; + float3 _Screen; + float _SpawnHeuristic; + + sampler2D_float _CameraDepthTexture; + sampler2D _BlurredColor; + sampler2D _MainTex; + sampler2D _FgCocMask; + + struct appendStruct { + float3 pos; + float4 color; + }; + + struct gs_out { + float4 pos : SV_POSITION; + float3 uv : TEXCOORD0; + float4 color : TEXCOORD1; + float4 misc : TEXCOORD2; + }; + + // TODO: activate border clamp tex sampler state instead? + inline float4 clampBorderColor(float2 uv) + { +#if 1 + if(uv.x<=0) return BOKEH_ZERO_VEC; if(uv.x>=1) return BOKEH_ZERO_VEC; + if(uv.y<=0) return BOKEH_ZERO_VEC; if(uv.y>=1) return BOKEH_ZERO_VEC; +#endif + return BOKEH_ONE_VEC; + } + + struct vs_out { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 color : TEXCOORD1; + float cocOverlap : TEXCOORD2; + }; + + struct appdata { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + + struct v2f { + float4 pos : SV_POSITION; + float2 uv_flip : TEXCOORD0; + float2 uv : TEXCOORD1; + }; + + AppendStructuredBuffer pointBufferOutput : register(u1); + StructuredBuffer pointBuffer; + + vs_out vertApply (uint id : SV_VertexID) + { + vs_out o = (vs_out)0; + float2 pos = pointBuffer[id].pos.xy ; + o.pos = float4(pos * 2.0 - 1.0, 0, 1); + o.color = pointBuffer[id].color; + #if UNITY_UV_STARTS_AT_TOP + o.pos.y *= -1; + #endif + o.cocOverlap = pointBuffer[id].pos.z; + + return o; + } + + v2f vertCollect (appdata v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; + o.uv_flip = v.texcoord; + #if UNITY_UV_STARTS_AT_TOP + if(_MainTex_TexelSize.y<0) + o.uv_flip.y = 1.0-o.uv_flip.y; + if(_MainTex_TexelSize.y<0) + o.pos.y *= -1.0; + #endif + return o; + } + + [maxvertexcount(4)] + void geom (point vs_out input[1], inout TriangleStream outStream) + { + // NEW ENERGY CONSERVATION: + float2 scale2 = _BokehParams.ww * input[0].color.aa * _BokehParams.xx; + float4 offs = 0; + offs.xy = float2(3.0, 3.0) + 2.0f * floor(scale2 + float2(0.5,0.5)); + + float2 rs = ((float2(1.0, 1.0) + 2.0f * (scale2 + float2(0.5,0.5))));; + float2 f2 = offs.xy / rs; + + float energyAdjustment = (_BokehParams.y) / (rs.x*rs.y); + offs.xy *= _Screen.xy; + + gs_out output; + + output.pos = input[0].pos + offs*float4(-1,1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(0, 1, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1,1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(1, 1, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(-1,-1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(0, 0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1,-1,0,0); + output.misc = float4(f2,0,0); + output.uv = float3(1, 0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + outStream.RestartStrip(); + } + + float4 collectBrightPixel(half2 uv) + { + half4 c = tex2D (_MainTex, uv); + half coc = abs(c.a); + half lumc = Luminance (c.rgb); + + half4 cblurred = tex2D (_BlurredColor, uv); + half cocBlurred = abs(cblurred.a); + half lumblurred = Luminance (cblurred.rgb); + half fgCoc = -min(c.a,0.0h); + + [branch] + if (coc * _BokehParams.w > 1 && cocBlurred > 0.1 && lumc > _BokehParams.z && abs(lumc-lumblurred) > _SpawnHeuristic) + { + appendStruct append = (appendStruct)0; + append.pos = float3(uv, fgCoc); + append.color.rgba = half4(c.rgb * saturate(coc*4), coc); + pointBufferOutput.Append(append); + c = half4(c.rgb * saturate(1-coc*4), c.a); + } + return c; + } + +ENDCG + +SubShader +{ + +// pass 0: bokeh splatting +Pass { + + ZWrite Off ZTest Always Cull Off + BlendOp Add, Add + Blend DstAlpha One, Zero One + ColorMask RGBA + + CGPROGRAM + + #pragma target 5.0 + #pragma vertex vertApply + #pragma geometry geom + #pragma fragment frag + + fixed4 frag (gs_out i) : SV_Target + { + float2 uv = (i.uv.xy) * i.misc.xy + (float2(1,1)-i.misc.xy) * 0.5; // smooth uv scale + return float4(i.color.rgb, 1) * float4(tex2D(_MainTex, uv.xy).rgb, i.uv.z) * clampBorderColor (uv); + } + + ENDCG +} + +// pass 1: append buffer "collect" +Pass +{ + ZWrite Off ZTest Always Cull Off + + CGPROGRAM + + #pragma vertex vertCollect + #pragma fragment frag + #pragma target 5.0 + + float4 frag (v2f i) : SV_Target + { + return collectBrightPixel(i.uv); + } + ENDCG +} + + +} + +Fallback Off +} diff --git a/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta b/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta new file mode 100644 index 0000000..b36b645 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Resources/BokehSplatting.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c961b8ed1f00f924d804ada5143bd0e8 +timeCreated: 1449750679 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader b/Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader new file mode 100644 index 0000000..a049886 --- /dev/null +++ b/Assets/Cinematic Effects/DepthOfField/Resources/DepthOfField.shader @@ -0,0 +1,1447 @@ +Shader "Hidden/DepthOfField/DepthOfField" +{ + +Properties +{ + _MainTex ("-", 2D) = "black" + _SecondTex ("-", 2D) = "black" + _ThirdTex ("-", 2D) = "black" +} + +CGINCLUDE +#pragma target 3.0 +#pragma fragmentoption ARB_precision_hint_fastest +#include "UnityCG.cginc" + +//undef USE_LOCAL_TONEMAPPING if you dont want to use local tonemapping. +//tweaking these values down will trade stability for less bokeh (see Tonemap/ToneMapInvert methods below). +#ifndef SHADER_API_MOBILE + #define USE_LOCAL_TONEMAPPING +#endif +#define LOCAL_TONEMAP_START_LUMA 1.0 +#define LOCAL_TONEMAP_RANGE_LUMA 5.0 + +sampler2D _SecondTex; +sampler2D _ThirdTex; + +uniform half4 _MainTex_TexelSize; +uniform half4 _BlurCoe; +uniform half4 _BlurParams; +uniform half4 _BoostParams; +uniform half4 _Convolved_TexelSize; +uniform float4 _Offsets; + +uniform half4 _MainTex_ST; +uniform half4 _SecondTex_ST; +uniform half4 _ThirdTex_ST; + +#if (SHADER_TARGET >= 50 && !defined(SHADER_API_PSSL)) + #define USE_TEX2DOBJECT_FOR_COC +#endif + +#if defined(USE_TEX2DOBJECT_FOR_COC) + Texture2D _CameraDepthTexture; + SamplerState sampler_CameraDepthTexture; + Texture2D _MainTex; + SamplerState sampler_MainTex; +#else + sampler2D _MainTex; + sampler2D _CameraDepthTexture; +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Verter Shaders and declaration +/////////////////////////////////////////////////////////////////////////////// + +struct v2f +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv1 : TEXCOORD1; +}; + +struct v2fDepth +{ + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; +}; + +struct v2fBlur +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 uv01 : TEXCOORD1; + float4 uv23 : TEXCOORD2; + float4 uv45 : TEXCOORD3; + float4 uv67 : TEXCOORD4; + float4 uv89 : TEXCOORD5; +}; + +v2fDepth vert(appdata_img v) +{ + v2fDepth o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; +#if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1-o.uv.y; +#endif + return o; +} + +v2fDepth vertNoFlip(appdata_img v) +{ + v2fDepth o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; +} + +v2f vert_d( appdata_img v ) +{ + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv1.xy = v.texcoord.xy; + o.uv.xy = v.texcoord.xy; + +#if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1-o.uv.y; +#endif + + return o; +} + +v2f vertFlip( appdata_img v ) +{ + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv1.xy = v.texcoord.xy; + o.uv.xy = v.texcoord.xy; + +#if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1-o.uv.y; + if (_MainTex_TexelSize.y < 0) + o.uv1.y = 1-o.uv1.y; +#endif + + return o; +} + +v2fBlur vertBlurPlusMinus (appdata_img v) +{ + v2fBlur o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv.xy = v.texcoord.xy; + o.uv01 = v.texcoord.xyxy + _Offsets.xyxy * float4(1,1, -1,-1) * _MainTex_TexelSize.xyxy / 6.0; + o.uv23 = v.texcoord.xyxy + _Offsets.xyxy * float4(2,2, -2,-2) * _MainTex_TexelSize.xyxy / 6.0; + o.uv45 = v.texcoord.xyxy + _Offsets.xyxy * float4(3,3, -3,-3) * _MainTex_TexelSize.xyxy / 6.0; + o.uv67 = v.texcoord.xyxy + _Offsets.xyxy * float4(4,4, -4,-4) * _MainTex_TexelSize.xyxy / 6.0; + o.uv89 = v.texcoord.xyxy + _Offsets.xyxy * float4(5,5, -5,-5) * _MainTex_TexelSize.xyxy / 6.0; + return o; +} + +/////////////////////////////////////////////////////////////////////////////// +// Helpers +/////////////////////////////////////////////////////////////////////////////// + +inline half4 FetchMainTex(float2 uv) +{ +#if defined(USE_TEX2DOBJECT_FOR_COC) + return _MainTex.SampleLevel(sampler_MainTex, uv, 0); +#else + return tex2Dlod (_MainTex, float4(uv,0,0)); +#endif +} + +inline half2 GetBilinearFetchTexOffsetFromAbsCoc(half4 absCoc) +{ + half4 cocWeights = absCoc * absCoc * absCoc; + + half2 offset = 0; + offset += cocWeights.r * float2(-1,+1); + offset += cocWeights.g * float2(+1,+1); + offset += cocWeights.b * float2(+1,-1); + offset += cocWeights.a * float2(-1,-1); + offset = clamp((half2)-1,(half2)1, offset); + offset *= 0.5; + return offset; +} + +inline half4 FetchColorAndCocFromMainTex(float2 uv, float2 offsetFromKernelCenter) +{ + //bilinear + half4 fetch = FetchMainTex(uv); + +//coc can't be linearly interpolated while doing "scatter and gather" or we will have haloing where coc vary sharply. +#if defined(USE_SPECIAL_FETCH_FOR_COC) + + #if defined(USE_TEX2DOBJECT_FOR_COC) + half4 allCoc = _MainTex.GatherAlpha(sampler_MainTex, uv); + half cocAB = (abs(allCoc.r) instead point sample the coc from the fartest away texel (not as good). + half2 bilinearCenter = floor(uv * _MainTex_TexelSize.zw - 0.5) + 1.0; + half2 cocUV = bilinearCenter + 0.5 * sign(offsetFromKernelCenter); + half coc = tex2Dlod (_MainTex, float4( cocUV * _MainTex_TexelSize.xy,0,0)).a; + #endif + + fetch.a = coc; +#endif + return fetch; +} + +inline half3 getBoostAmount(half4 colorAndCoc) +{ + half boost = colorAndCoc.a * (colorAndCoc.a < 0.0f ?_BoostParams.x:_BoostParams.y); + half luma = dot(colorAndCoc.rgb, half3(0.3h, 0.59h, 0.11h)); + return luma < _BoostParams.z ? half3(0.0h, 0.0h, 0.0h):colorAndCoc.rgb * boost.rrr; +} + +inline half GetCocFromZValue(half d, bool useExplicit) +{ + d = Linear01Depth (d); + + if (useExplicit) + { + half coc = d < _BlurCoe.z ? clamp((_BlurParams.x * d + _BlurParams.y), -1.0f, 0.0f):clamp((_BlurParams.z * d + _BlurParams.w), 0.0f, 1.0f); + return coc; + } + else + { + half aperture = _BlurParams.x; + half focalLength = _BlurParams.y; + half focusDistance01 = _BlurParams.z; + half focusRange01 = _BlurParams.w; + half coc = aperture * abs(d - focusDistance01) / (d + 1e-5f) - focusRange01; + coc = (d < focusDistance01 ? -1.0h:1.0h) * clamp(coc, 0.0f, 1.0f); + return coc; + } +} + +inline half GetCocFromDepth(half2 uv, bool useExplicit) +{ +#if defined(USE_TEX2DOBJECT_FOR_COC) + half d = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, uv, 0); +#else + half d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); +#endif + return GetCocFromZValue(d,useExplicit); +} + +#if (SHADER_TARGET < 50 && !defined(SHADER_API_PSSL)) + half rcp(half x) { return 1 / x; } +#endif + +//from http://graphicrants.blogspot.dk/2013/12/tone-mapping.html +inline half3 Tonemap(half3 color) +{ +#ifdef USE_LOCAL_TONEMAPPING + half a = LOCAL_TONEMAP_START_LUMA; + half b = LOCAL_TONEMAP_RANGE_LUMA; + + half luma = max(color.r, max(color.g, color.b)); + if (luma <= a) + return color; + + return color * rcp(luma) * (a*a - b * luma) / (2*a - b - luma); +#else + return color; +#endif +} + +inline half3 ToneMapInvert(half3 color) +{ +#ifdef USE_LOCAL_TONEMAPPING + half a = LOCAL_TONEMAP_START_LUMA; + half b = LOCAL_TONEMAP_RANGE_LUMA; + + half luma = max(color.r, max(color.g, color.b)); + if (luma <= a) + return color; + + return color * rcp(luma) * (a*a - (2*a - b) * luma) / (b - luma); +#else + return color; +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +// Directional (hexagonal/octogonal) bokeh +/////////////////////////////////////////////////////////////////////////////// + +#define SAMPLE_NUM_L 6 +#define SAMPLE_NUM_M 11 +#define SAMPLE_NUM_H 16 + +inline half4 shapeDirectionalBlur(half2 uv, bool mergePass, int numSample, bool sampleDilatedFG) +{ + half4 centerTap = FetchMainTex(uv); + half fgCoc = centerTap.a; + half fgBlendFromPreviousPass = centerTap.a * _Offsets.z; + if (sampleDilatedFG) + { + half2 cocs = tex2Dlod(_SecondTex, half4(uv,0,0)).rg; + fgCoc = min(cocs.r, cocs.g); + centerTap.a = cocs.g; + } + + half bgRadius = smoothstep(0.0h, 0.85h, centerTap.a) * _BlurCoe.y; + half fgRadius = smoothstep(0.0h, 0.85h, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + if (radius < 1e-2f ) + { + return half4(centerTap.rgb, (sampleDilatedFG||mergePass)?fgBlendFromPreviousPass:centerTap.a); + } + + half radOtherFgRad = radius/(fgRadius + 1e-2h); + half radOtherBgRad = radius/(bgRadius + 1e-2h); + half2 range = radius * _MainTex_TexelSize.xy; + + half fgWeight = 0.001h; + half bgWeight = 0.001h; + half3 fgSum = half3(0,0,0); + half3 bgSum = half3(0,0,0); + + for (int k = 0; k < numSample; k++) + { + half t = (half)k / half(numSample-1); + half2 kVal = lerp(_Offsets.xy, -_Offsets.xy, t); + half2 offset = kVal * range; + half2 texCoord = uv + offset; + half4 sample0 = FetchColorAndCocFromMainTex(texCoord, offset); + if (sampleDilatedFG) + { + sample0.a = tex2Dlod(_SecondTex, half4(texCoord,0,0)).g; + } + + half dist = abs(2.0h * t - 1); + half distanceFactor = saturate(-0.5f * abs(sample0.a - centerTap.a) * dist + 1.0f); + half isNear = max(0.0h, -sample0.a); + half isFar = max(0.0h, sample0.a) * distanceFactor; + isNear *= 1- smoothstep(1.0h, 2.0h, dist * radOtherFgRad); + isFar *= 1- smoothstep(1.0h, 2.0h, dist * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 0.0001h); + half3 bgColor = bgSum / (bgWeight + 0.0001h); + half bgBlend = saturate (2.0h * bgWeight / numSample); + half fgBlend = saturate (2.0h * fgWeight / numSample); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0h , -centerTap.a) , fgBlend)); + + if (mergePass) + { + finalColor = min(finalColor, tex2Dlod(_ThirdTex, half4(uv,0,0)).rgb); + } + + finalColor = lerp(centerTap.rgb, finalColor, saturate(bgBlend+fgBlend)); + fgBlend = max(fgBlendFromPreviousPass, fgBlend); + return half4(finalColor, (sampleDilatedFG||mergePass)?fgBlend:centerTap.a); +} + +half4 fragShapeLowQuality(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, false); +} + +half4 fragShapeLowQualityDilateFg(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, true); +} + +half4 fragShapeLowQualityMerge(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, false); +} + +half4 fragShapeLowQualityMergeDilateFg(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, true); +} + +half4 fragShapeMediumQuality(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, false); +} + +half4 fragShapeMediumQualityDilateFg(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, true); +} + +half4 fragShapeMediumQualityMerge(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, false); +} + +half4 fragShapeMediumQualityMergeDilateFg(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, true); +} + +half4 fragShapeHighQuality(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, false); +} + +half4 fragShapeHighQualityDilateFg(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, true); +} + +half4 fragShapeHighQualityMerge(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, false); +} + +half4 fragShapeHighQualityMergeDilateFg(v2fDepth i) : SV_Target +{ + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, true); +} + +/////////////////////////////////////////////////////////////////////////////// +// Disk Bokeh +/////////////////////////////////////////////////////////////////////////////// + +static const half3 DiscBokeh48[48] = +{ + //48 tap regularly spaced circular kernel (x,y, length) + //fill free to change the shape to try other bokehs style :) + half3( 0.99144h, 0.13053h, 1.0h), + half3( 0.92388h, 0.38268h, 1.0h), + half3( 0.79335h, 0.60876h, 1.0h), + half3( 0.60876h, 0.79335h, 1.0h), + half3( 0.38268h, 0.92388h, 1.0h), + half3( 0.13053h, 0.99144h, 1.0h), + half3(-0.13053h, 0.99144h, 1.0h), + half3(-0.38268h, 0.92388h, 1.0h), + half3(-0.60876h, 0.79335h, 1.0h), + half3(-0.79335h, 0.60876h, 1.0h), + half3(-0.92388h, 0.38268h, 1.0h), + half3(-0.99144h, 0.13053h, 1.0h), + half3(-0.99144h,-0.13053h, 1.0h), + half3(-0.92388h,-0.38268h, 1.0h), + half3(-0.79335h,-0.60876h, 1.0h), + half3(-0.60876h,-0.79335h, 1.0h), + half3(-0.38268h,-0.92388h, 1.0h), + half3(-0.13053h,-0.99144h, 1.0h), + half3( 0.13053h,-0.99144h, 1.0h), + half3( 0.38268h,-0.92388h, 1.0h), + half3( 0.60876h,-0.79335h, 1.0h), + half3( 0.79335h,-0.60876h, 1.0h), + half3( 0.92388h,-0.38268h, 1.0h), + half3( 0.99144h,-0.13053h, 1.0h), + half3( 0.64732h, 0.12876h, 0.66h), + half3( 0.54877h, 0.36668h, 0.66h), + half3( 0.36668h, 0.54877h, 0.66h), + half3( 0.12876h, 0.64732h, 0.66h), + half3(-0.12876h, 0.64732h, 0.66h), + half3(-0.36668h, 0.54877h, 0.66h), + half3(-0.54877h, 0.36668h, 0.66h), + half3(-0.64732h, 0.12876h, 0.66h), + half3(-0.64732h,-0.12876h, 0.66h), + half3(-0.54877h,-0.36668h, 0.66h), + half3(-0.36668h,-0.54877h, 0.66h), + half3(-0.12876h,-0.64732h, 0.66h), + half3( 0.12876h,-0.64732h, 0.66h), + half3( 0.36668h,-0.54877h, 0.66h), + half3( 0.54877h,-0.36668h, 0.66h), + half3( 0.64732h,-0.12876h, 0.66h), + half3( 0.30488h, 0.12629h, 0.33h), + half3( 0.12629h, 0.30488h, 0.33h), + half3(-0.12629h, 0.30488h, 0.33h), + half3(-0.30488h, 0.12629h, 0.33h), + half3(-0.30488h,-0.12629h, 0.33h), + half3(-0.12629h,-0.30488h, 0.33h), + half3( 0.12629h,-0.30488h, 0.33h), + half3( 0.30488h,-0.12629h, 0.33h) +}; + +inline half4 circleCocBokeh(half2 uv, bool sampleDilatedFG, int increment) +{ + half4 centerTap = FetchMainTex(uv); + half fgCoc = centerTap.a; + if (sampleDilatedFG) + { + fgCoc = min(tex2Dlod(_SecondTex, half4(uv,0,0)).r, fgCoc); + } + + half bgRadius = 0.5h * smoothstep(0.0h, 0.85h, centerTap.a) * _BlurCoe.y; + half fgRadius = 0.5h * smoothstep(0.0h, 0.85h, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + if (radius < 1e-2f ) + { + return half4(centerTap.rgb, 0); + } + + half2 poissonScale = radius * _MainTex_TexelSize.xy; + half fgWeight = max(0,-centerTap.a); + half bgWeight = max(0, centerTap.a); + half3 fgSum = centerTap.rgb * fgWeight; + half3 bgSum = centerTap.rgb * bgWeight; + + half radOtherFgRad = radius/(fgRadius + 1e-2h); + half radOtherBgRad = radius/(bgRadius + 1e-2h); + + for (int l = 0; l < 48; l+= increment) + { + half2 sampleUV = uv + DiscBokeh48[l].xy * poissonScale.xy; + half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscBokeh48[l].xy); + + half isNear = max(0.0h, -sample0.a); + half distanceFactor = saturate(-0.5f * abs(sample0.a - centerTap.a) * DiscBokeh48[l].z + 1.0f); + half isFar = max(0.0h, sample0.a) * distanceFactor; + isNear *= 1- smoothstep(1.0h, 2.0h, DiscBokeh48[l].z * radOtherFgRad); + isFar *= 1- smoothstep(1.0h, 2.0h, DiscBokeh48[l].z * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 0.0001h); + half3 bgColor = bgSum / (bgWeight + 0.0001h); + half bgBlend = saturate (2.0h * bgWeight / 49.0h); + half fgBlend = saturate (2.0h * fgWeight / 49.0h); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0h , -centerTap.a) , fgBlend)); + half4 returnValue = half4(finalColor, fgBlend ); + + return returnValue; +} + +half4 fragCircleBlurWithDilatedFg (v2fDepth i) : SV_Target +{ + return circleCocBokeh(i.uv, true, 1); +} + +half4 fragCircleBlur (v2fDepth i) : SV_Target +{ + return circleCocBokeh(i.uv, false, 1); +} + +half4 fragCircleBlurWithDilatedFgLowQuality (v2fDepth i) : SV_Target +{ + return circleCocBokeh(i.uv, true, 2); +} + +half4 fragCircleBlurLowQuality (v2fDepth i) : SV_Target +{ + return circleCocBokeh(i.uv, false, 2); +} + +/////////////////////////////////////////////////////////////////////////////// +// Prefilter blur +/////////////////////////////////////////////////////////////////////////////// + +#define DISC_PREFILTER_SAMPLE 9 +static const half2 DiscPrefilter[DISC_PREFILTER_SAMPLE] = +{ + half2(0.01288369f, 0.5416069f), + half2(-0.9192798f, -0.09529364f), + half2(0.7596578f, 0.1922738f), + half2(-0.14132f, -0.2880242f), + half2(-0.5249333f, 0.7777638f), + half2(-0.5871695f, -0.7403569f), + half2(0.3202196f, -0.6442268f), + half2(0.8553214f, -0.3920982f), + half2(0.5827708f, 0.7599297f) +}; + +half4 fragCocPrefilter (v2fDepth i) : SV_Target +{ + half4 centerTap = FetchMainTex(i.uv); + half radius = 0.33h * 0.5h * (centerTap.a < 0.0f ? -(centerTap.a * _BlurCoe.x):(centerTap.a * _BlurCoe.y)); + half2 poissonScale = radius * _MainTex_TexelSize.xy; + + if (radius < 0.01h ) + { + return centerTap; + } + + half sampleCount = 1; + half3 sum = centerTap.rgb * 1; + for (int l = 0; l < DISC_PREFILTER_SAMPLE; l++) + { + half2 sampleUV = i.uv + DiscPrefilter[l].xy * poissonScale.xy; + half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscPrefilter[l].xy); + half weight = max(sample0.a * centerTap.a,0.0h); + sum += sample0.rgb * weight; + sampleCount += weight; + } + + half4 returnValue = half4(sum / sampleCount, centerTap.a); + return returnValue; +} + +/////////////////////////////////////////////////////////////////////////////// +// Final merge and upsample +/////////////////////////////////////////////////////////////////////////////// + +inline half4 upSampleConvolved(half2 uv, bool useBicubic, bool useExplicit) +{ + half2 convolvedTexelPos = uv * _Convolved_TexelSize.xy; + half2 convolvedTexelCenter = floor( convolvedTexelPos ) + 0.5; + half2 convolvedTexelOffsetFromCenter = convolvedTexelPos - convolvedTexelCenter; + half2 offsetFromCoc = 0; + +#if defined(USE_TEX2DOBJECT_FOR_COC) + half2 cocUV = (convolvedTexelOffsetFromCenter * _Convolved_TexelSize.zw) + uv; + half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, cocUV); + coc.r = GetCocFromZValue(coc.r, useExplicit); + coc.g = GetCocFromZValue(coc.g, useExplicit); + coc.b = GetCocFromZValue(coc.b, useExplicit); + coc.a = GetCocFromZValue(coc.a, useExplicit); + + half4 absCoc = abs(coc); + offsetFromCoc = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * 0.5; + uv += offsetFromCoc * _Convolved_TexelSize.zw; +#endif + + if (useBicubic) + { + //bicubic upsampling (B-spline) + //adding offsetFromCoc "antialias" haloing from bright in focus region on dark out of focus region. + //however its a hack as we should consider all the COC of the bicubic region and kill the bicubic + //interpolation to avoid in any leaking but that would be too expensive, so when this is a problem + //one should rather disable bicubic interpolation. + half2 f = convolvedTexelOffsetFromCenter + offsetFromCoc; + half2 f2 = f * f; + half2 f3 = f * f2; + + half2 w0 = -0.166h * f3 + 0.5h * f2 - 0.5h * f + 0.166h; + half2 w1 = 0.5h * f3 - f2 + 0.666h; + half2 w3 = 0.166h * f3; + half2 w2 = 1.0h - w0 - w1 - w3; + + half2 s0 = w0 + w1; + half2 s1 = w2 + w3; + half2 f0 = w1 / s0; + half2 f1 = w3 / s1; + + half2 t0 = _Convolved_TexelSize.zw * (convolvedTexelCenter - 1.0h + f0); + half2 t1 = _Convolved_TexelSize.zw * (convolvedTexelCenter + 1.0h + f1); + + return tex2Dlod(_SecondTex, half4(t0.x, t0.y, 0, 0)) * s0.x * s0.y + + tex2Dlod(_SecondTex, half4(t1.x, t0.y, 0, 0)) * s1.x * s0.y + + tex2Dlod(_SecondTex, half4(t0.x, t1.y, 0, 0)) * s0.x * s1.y + + tex2Dlod(_SecondTex, half4(t1.x, t1.y, 0, 0)) * s1.x * s1.y; + } + else + { + return tex2Dlod(_SecondTex, half4(uv,0,0)); + } +} + +inline half4 dofMerge (half2 uv, bool useExplicit, bool useBicubic) +{ + half4 convolvedTap = upSampleConvolved(uv, useBicubic, useExplicit); + convolvedTap.rgb = ToneMapInvert(convolvedTap.rgb); + + half4 sourceTap = FetchMainTex(uv); + half coc = GetCocFromDepth(uv, useExplicit); + + sourceTap.rgb += getBoostAmount(half4(sourceTap.rgb, coc)); + + coc = (coc * _BlurCoe.y > 1.0h )?coc:0.0h; + half blendValue = smoothstep(0.0, 0.33h, max(coc, convolvedTap.a)); + half3 returnValue = lerp(sourceTap.rgb, convolvedTap.rgb, blendValue); + return (blendValue < 1e-2f) ? sourceTap : half4(returnValue.rgb, sourceTap.a); +} + +half4 fragMergeBicubic (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, false, true); +} + +half4 fragMergeExplicitBicubic (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, true, true); +} + +half4 fragMerge (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, false, false); +} + +half4 fragMergeExplicit (v2fDepth i) : SV_Target +{ + return dofMerge(i.uv, true, false); +} + +/////////////////////////////////////////////////////////////////////////////// +// Downsampling and COC computation +/////////////////////////////////////////////////////////////////////////////// + +inline half4 captureCoc(half2 uvColor, half2 uvDepth, bool useExplicit) +{ + /*****************/ + /* coc.a | coc.b */ + /* coc.r | coc.g */ + /*****************/ +#if defined(USE_TEX2DOBJECT_FOR_COC) + half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, uvDepth); + coc.r = GetCocFromZValue(coc.r, useExplicit); + coc.g = GetCocFromZValue(coc.g, useExplicit); + coc.b = GetCocFromZValue(coc.b, useExplicit); + coc.a = GetCocFromZValue(coc.a, useExplicit); +#else + half4 coc; + coc.r = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25f,+0.25f), useExplicit); + coc.g = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(+0.25f,+0.25f), useExplicit); + coc.b = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(+0.25f,-0.25f), useExplicit); + coc.a = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25f,-0.25f), useExplicit); +#endif + + half4 absCoc = abs(coc); + half2 offset = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * _MainTex_TexelSize.xy; + half4 color = FetchMainTex(uvColor + offset); + + half cocRG = (absCoc.r> m_GroupFields = new Dictionary>(); + private List m_SimpleProperties = new List(); + private List m_AdvancedProperties = new List(); + + private LensAberrations concreteTarget + { + get { return target as LensAberrations; } + } + + private void PopulateMap(FieldInfo group) + { + var searchPath = group.Name + "."; + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + { + settingsGroup.Add(property); + + if (setting.GetCustomAttributes(typeof(LensAberrations.SimpleSetting), false).Length > 0) + m_SimpleProperties.Add(property); + else if (setting.GetCustomAttributes(typeof(LensAberrations.AdvancedSetting), false).Length > 0) + m_AdvancedProperties.Add(property); + } + } + } + + private void OnEnable() + { + var settingsGroups = typeof(LensAberrations).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(LensAberrations.SettingsGroup), false).Any()); + + foreach (var settingGroup in settingsGroups) + PopulateMap(settingGroup); + } + + private void DrawFields() + { + foreach (var group in m_GroupFields) + { + var enabledField = group.Value.FirstOrDefault(x => x.propertyPath == group.Key.Name + ".enabled"); + var groupProperty = serializedObject.FindProperty(group.Key.Name); + + GUILayout.Space(5); + bool display = EditorGUIHelper.Header(groupProperty, enabledField); + if (!display) + continue; + + GUILayout.BeginHorizontal(); + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + { + GUILayout.Space(3); + foreach (var field in group.Value.Where(x => x.propertyPath != group.Key.Name + ".enabled")) + { + if (group.Key.FieldType == typeof(LensAberrations.VignetteSettings)) + { + if (m_SimpleProperties.Contains(field) && concreteTarget.vignette.mode != LensAberrations.SettingsMode.Simple || + m_AdvancedProperties.Contains(field) && concreteTarget.vignette.mode != LensAberrations.SettingsMode.Advanced) + continue; + } + else + { + if (m_AdvancedProperties.Contains(field) && concreteTarget.chromaticAberration.mode != LensAberrations.SettingsMode.Advanced) + continue; + } + + EditorGUILayout.PropertyField(field); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + DrawFields(); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta b/Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta new file mode 100644 index 0000000..6b7344e --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8becb41f431ef90468376f6c5845e0bd +timeCreated: 1454680396 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs new file mode 100644 index 0000000..3046820 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs @@ -0,0 +1,328 @@ +using UnityEngine; +using System; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Lens Aberrations")] + public class LensAberrations : MonoBehaviour + { + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class SimpleSetting : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class AdvancedSetting : Attribute + {} + #endregion + + #region Settings + public enum SettingsMode + { + Simple, + Advanced + } + + [Serializable] + public struct DistortionSettings + { + public bool enabled; + + [Range(-100f, 100f), Tooltip("Distortion amount.")] + public float amount; + + [Range(0f, 1f), Tooltip("Distortion center point (X axis).")] + public float centerX; + + [Range(0f, 1f), Tooltip("Distortion center point (Y axis).")] + public float centerY; + + [Range(0f, 2f), Tooltip("Amount multiplier on X axis.")] + public float amountX; + + [Range(0f, 2f), Tooltip("Amount multiplier on Y axis.")] + public float amountY; + + [Range(0.5f, 2f), Tooltip("Global screen scaling.")] + public float scale; + + public static DistortionSettings defaultSettings + { + get + { + return new DistortionSettings + { + enabled = false, + amount = 0f, + centerX = 0.5f, + centerY = 0.5f, + amountX = 1f, + amountY = 1f, + scale = 1f + }; + } + } + } + + [Serializable] + public struct VignetteSettings + { + public bool enabled; + + [Tooltip("Use the \"Advanced\" mode if you need more control over the vignette shape and smoothness at the expense of performances.")] + public SettingsMode mode; + + [Tooltip("Vignette color. Use the alpha channel for transparency.")] + public Color color; + + [SimpleSetting, Range(0f, 3f), Tooltip("Amount of vignetting on screen.")] + public float intensity; + + [SimpleSetting, Range(0.1f, 3f), Tooltip("Smoothness of the vignette borders.")] + public float smoothness; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Vignette radius in screen coordinates.")] + public float radius; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Smoothness of the vignette border. Tweak this at the same time as \"Falloff\" to get more control over the vignette gradient.")] + public float spread; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Smoothness of the vignette border. Tweak this at the same time as \"Spread\" to get more control over the vignette gradient.")] + public float falloff; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Lower values will make a square-ish vignette.")] + public float roundness; + + [Range(0f, 1f), Tooltip("Blurs the corners of the screen. Leave this at 0 to disable it.")] + public float blur; + + [Range(0f, 1f), Tooltip("Desaturate the corners of the screen. Leave this to 0 to disable it.")] + public float desaturate; + + public static VignetteSettings defaultSettings + { + get + { + return new VignetteSettings + { + enabled = false, + mode = SettingsMode.Simple, + color = Color.black, + intensity = 1.2f, + smoothness = 1.5f, + radius = 0.7f, + spread = 0.4f, + falloff = 0.5f, + roundness = 1f, + blur = 0f, + desaturate = 0f + }; + } + } + } + + [Serializable] + public struct ChromaticAberrationSettings + { + public bool enabled; + + [Tooltip("Use the \"Advanced\" mode if you need more control over the chromatic aberrations at the expense of performances.")] + public SettingsMode mode; + + [Range(-2f, 2f)] + public float tangential; + + [AdvancedSetting, Range(0f, 2f)] + public float axial; + + [AdvancedSetting, Range(0f, 2f)] + public float contrastDependency; + + public static ChromaticAberrationSettings defaultSettings + { + get + { + return new ChromaticAberrationSettings + { + enabled = false, + mode = SettingsMode.Simple, + tangential = 0f, + axial = 0f, + contrastDependency = 0f + }; + } + } + } + #endregion + + [SettingsGroup] + public DistortionSettings distortion = DistortionSettings.defaultSettings; + + [SettingsGroup] + public VignetteSettings vignette = VignetteSettings.defaultSettings; + + [SettingsGroup] + public ChromaticAberrationSettings chromaticAberration = ChromaticAberrationSettings.defaultSettings; + + private enum Pass + { + BlurPrePass, + Simple, + Desaturate, + Blur, + BlurDesaturate, + ChromaticAberrationOnly, + DistortOnly + } + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/LensAberrations"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, false, this)) + enabled = false; + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (!vignette.enabled && !chromaticAberration.enabled && !distortion.enabled) + { + Graphics.Blit(source, destination); + return; + } + + material.DisableKeyword("DISTORT"); + material.DisableKeyword("UNDISTORT"); + + if (distortion.enabled) + { + float amount = 1.6f * Math.Max(Mathf.Abs(distortion.amount), 1f); + float theta = 0.01745329251994f * Math.Min(160f, amount); + float sigma = 2f * Mathf.Tan(theta * 0.5f); + Vector4 p0 = new Vector4(2f * distortion.centerX - 1f, 2f * distortion.centerY - 1f, distortion.amountX, distortion.amountY); + Vector3 p1 = new Vector3(distortion.amount >= 0f ? theta : 1f / theta, sigma, 1f / distortion.scale); + material.SetVector("_DistCenterScale", p0); + material.SetVector("_DistAmount", p1); + + if (distortion.amount >= 0f) + material.EnableKeyword("DISTORT"); + else + material.EnableKeyword("UNDISTORT"); + } + + material.SetColor("_VignetteColor", vignette.color); + + if (vignette.mode == SettingsMode.Simple) + { + material.SetVector("_Vignette1", new Vector4(vignette.intensity, vignette.smoothness, vignette.blur, 1f - vignette.desaturate)); + material.DisableKeyword("VIGNETTE_ADVANCED"); + } + else + { + float r1 = 0.5f * vignette.radius; + float r2 = r1 + vignette.spread; + float falloff = Math.Max(0.000001f, (1f - vignette.falloff) * 0.5f); + float roundness = (1f - vignette.roundness) * 6f + vignette.roundness * 2f; + material.SetVector("_Vignette1", new Vector4(r1, 1f / (r2 - r1), vignette.blur, 1f - vignette.desaturate)); + material.SetVector("_Vignette2", new Vector3(falloff, 0.5f / falloff, roundness)); + material.EnableKeyword("VIGNETTE_ADVANCED"); + } + + material.DisableKeyword("CHROMATIC_SIMPLE"); + material.DisableKeyword("CHROMATIC_ADVANCED"); + + if (chromaticAberration.enabled && !Mathf.Approximately(chromaticAberration.tangential, 0f)) + { + if (chromaticAberration.mode == SettingsMode.Advanced) + material.EnableKeyword("CHROMATIC_ADVANCED"); + else + material.EnableKeyword("CHROMATIC_SIMPLE"); + + Vector4 chromaParams = new Vector4(2.5f * chromaticAberration.tangential, 5f * chromaticAberration.axial, 5f / Mathf.Max(Mathf.Epsilon, chromaticAberration.contrastDependency), 5f); + material.SetVector("_ChromaticAberration", chromaParams); + } + + if (vignette.enabled && vignette.blur > 0f) + { + // Downscale + gaussian blur (2 passes) + int w = source.width / 2; + int h = source.height / 2; + RenderTexture tmp1 = RenderTexture.GetTemporary(w, h, 0, source.format); + RenderTexture tmp2 = RenderTexture.GetTemporary(w, h, 0, source.format); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(source, tmp1, material, (int)Pass.BlurPrePass); + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(tmp1, tmp2, material, (int)Pass.BlurPrePass); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(tmp2, tmp1, material, (int)Pass.BlurPrePass); + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(tmp1, tmp2, material, (int)Pass.BlurPrePass); + + material.SetTexture("_BlurTex", tmp2); + + if (vignette.desaturate > 0f) + Graphics.Blit(source, destination, material, (int)Pass.BlurDesaturate); + else + Graphics.Blit(source, destination, material, (int)Pass.Blur); + + RenderTexture.ReleaseTemporary(tmp2); + RenderTexture.ReleaseTemporary(tmp1); + } + else if (vignette.enabled && vignette.desaturate > 0f) + { + Graphics.Blit(source, destination, material, (int)Pass.Desaturate); + } + else if (vignette.enabled) + { + Graphics.Blit(source, destination, material, (int)Pass.Simple); + } + else if (chromaticAberration.enabled) + { + Graphics.Blit(source, destination, material, (int)Pass.ChromaticAberrationOnly); + } + else // Distortion enabled + { + Graphics.Blit(source, destination, material, (int)Pass.DistortOnly); + } + } + } +} diff --git a/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta new file mode 100644 index 0000000..9f89d38 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/LensAberrations.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: ff5335a7357baa3489a469d0ca0f40f3 +timeCreated: 1454589487 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_Shader: {fileID: 4800000, guid: 136ab50fe2b9ad64d9c22adc3668abb7, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/LensAberrations/Resources.meta b/Assets/Cinematic Effects/LensAberrations/Resources.meta new file mode 100644 index 0000000..711f7b8 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6580025651e0f284489694492cf3ce61 +folderAsset: yes +timeCreated: 1454583120 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader new file mode 100644 index 0000000..19e3550 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader @@ -0,0 +1,299 @@ +Shader "Hidden/LensAberrations" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma multi_compile __ DISTORT UNDISTORT + #pragma multi_compile __ CHROMATIC_SIMPLE CHROMATIC_ADVANCED + #pragma multi_compile __ VIGNETTE_ADVANCED + #include "UnityCG.cginc" + #pragma target 3.0 + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + half4 _DistCenterScale; + half3 _DistAmount; + half4 _ChromaticAberration; + half4 _Vignette1; + half3 _Vignette2; + half4 _VignetteColor; + + sampler2D _BlurTex; + half2 _BlurPass; + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv1 : TEXCOORD1; + half4 uv2 : TEXCOORD2; + }; + + v2f vert_blur_prepass(appdata_img v) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1.0 - o.uv.y; + #endif + + half2 d1 = 1.3846153846 * _BlurPass; + half2 d2 = 3.2307692308 * _BlurPass; + o.uv1 = half4(o.uv + d1, o.uv - d1); + o.uv2 = half4(o.uv + d2, o.uv - d2); + return o; + } + + half4 frag_blur_prepass(v2f i) : SV_Target + { + half4 color = tex2D(_MainTex, i.uv); + half3 c = color.rgb * 0.2270270270; + c += tex2D(_MainTex, i.uv1.xy).rgb * 0.3162162162; + c += tex2D(_MainTex, i.uv1.zw).rgb * 0.3162162162; + c += tex2D(_MainTex, i.uv2.xy).rgb * 0.0702702703; + c += tex2D(_MainTex, i.uv2.zw).rgb * 0.0702702703; + return half4(c, color.a); + } + + #define DISK_SAMPLE_NUM 9 + static const half2 SmallDiscKernel[DISK_SAMPLE_NUM] = + { + half2(-0.926212,-0.40581), + half2(-0.695914, 0.457137), + half2(-0.203345, 0.820716), + half2( 0.96234, -0.194983), + half2( 0.473434,-0.480026), + half2( 0.519456, 0.767022), + half2( 0.185461,-0.893124), + half2( 0.89642, 0.412458), + half2(-0.32194, -0.932615), + }; + + half4 chromaticAberration(half4 color, half2 uv) + { +#if CHROMATIC_SIMPLE + half2 coords = (uv - 0.5) * 2.0; + half2 uvg = uv - _MainTex_TexelSize.xy * _ChromaticAberration.x * coords * dot(coords, coords); + color.g = tex2D(_MainTex, uvg).g; +#elif CHROMATIC_ADVANCED + half2 coords = (uv - 0.5) * 2.0; + half tangentialStrength = _ChromaticAberration.x * dot(coords, coords); + half uvg = -(_ChromaticAberration.y > abs(tangentialStrength) ? sign(tangentialStrength) * _ChromaticAberration.y : tangentialStrength); + half2 offset = _MainTex_TexelSize.xy * uvg * coords; + half3 blurredTap = color.rgb * 0.1; + + for (int l = 0; l < DISK_SAMPLE_NUM; l++) + { + half2 sampleUV = uv + _MainTex_TexelSize.xy * SmallDiscKernel[l].xy + offset; + half3 tap = tex2D(_MainTex, sampleUV).rgb; + blurredTap += tap; + } + + blurredTap /= (half)DISK_SAMPLE_NUM + 0.2; + half contrast = saturate(_ChromaticAberration.z * Luminance(abs(blurredTap - color.rgb))); + color.g = lerp(color.g, blurredTap.g, contrast); +#endif + return color; + } + + half2 distort(half2 uv) + { +#if DISTORT + uv = (uv - 0.5) * _DistAmount.z + 0.5; + half2 ruv = _DistCenterScale.zw * (uv - 0.5 - _DistCenterScale.xy); + half ru = length(ruv); + half wu = ru * _DistAmount.x; + ru = tan(wu) * (1.0 / (ru * _DistAmount.y)); + uv = uv + ruv * (ru - 1.0); +#elif UNDISTORT + uv = (uv - 0.5) * _DistAmount.z + 0.5; + half2 ruv = _DistCenterScale.zw * (uv - 0.5 - _DistCenterScale.xy); + half ru = length(ruv); + ru = (1.0 / ru) * _DistAmount.x * atan(ru * _DistAmount.y); + uv = uv + ruv * (ru - 1.0); +#endif + return uv; + } + + half get_vignette_factor(half2 uv) + { +#if VIGNETTE_ADVANCED + uv = abs(uv - 0.5); + half x = saturate((pow(pow(uv.x, _Vignette2.z) + pow(uv.y, _Vignette2.z), 1.0 / _Vignette2.z) - _Vignette1.x) * _Vignette1.y); + half ix = 1.0 - x; + half v = _Vignette2.x == 0.5 ? x : x <= _Vignette2.x ? x * x / ((2.0 - _Vignette2.y) * x + _Vignette2.x * (_Vignette2.y - 1.0)) : 1.0 + ix * ix / ((_Vignette2.y - 2.0) * ix + (_Vignette2.x - 1.0) * (_Vignette2.y - 1.0)); + return 1.0 - v; +#else + half2 d = (uv - 0.5) * _Vignette1.x; + return pow(saturate(1.0 - dot(d, d)), _Vignette1.y); +#endif + } + + half4 vignette_simple(half4 color, half2 uv) + { + half v = get_vignette_factor(uv); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 vignette_desat(half4 color, half2 uv) + { + half v = get_vignette_factor(uv); + half lum = Luminance(color); + color.rgb = lerp(lerp(lum.xxx, color.rgb, _Vignette1.w), color.rgb, v); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 vignette_blur(half4 color, half2 uv) + { + half2 coords = (uv - 0.5) * 2.0; + half v = get_vignette_factor(uv); + half3 blur = tex2D(_BlurTex, uv); + color.rgb = lerp(color.rgb, blur, saturate(_Vignette1.z * dot(coords, coords))); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 vignette_blur_desat(half4 color, half2 uv) + { + half2 coords = (uv - 0.5) * 2.0; + half v = get_vignette_factor(uv); + half3 blur = tex2D(_BlurTex, uv); + color.rgb = lerp(color.rgb, blur, saturate(_Vignette1.z * dot(coords, coords))); + half lum = Luminance(color); + color.rgb = lerp(lerp(lum.xxx, color.rgb, _Vignette1.w), color.rgb, v); + color.rgb = lerp(_VignetteColor.rgb, color.rgb, lerp(1.0, v, _VignetteColor.a)); + return color; + } + + half4 frag_simple(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_simple(color, uv); + return color; + } + + half4 frag_desat(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_desat(color, uv); + return color; + } + + half4 frag_blur(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_blur(color, uv); + return color; + } + + half4 frag_blur_desat(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + color = vignette_blur_desat(color, uv); + return color; + } + + half4 frag_chroma_only(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 color = tex2D(_MainTex, uv); + color = chromaticAberration(color, uv); + return color; + } + + half4 frag_distort_only(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return tex2D(_MainTex, uv); + } + + ENDCG + + // (0) Blur pre-pass + Pass + { + CGPROGRAM + #pragma vertex vert_blur_prepass + #pragma fragment frag_blur_prepass + ENDCG + } + + // (1) Vignette simple + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_simple + ENDCG + } + + // (2) Vignette desat + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_desat + ENDCG + } + + // (3) Vignette blur + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_blur + ENDCG + } + + // (4) Vignette blur desat + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_blur_desat + ENDCG + } + + // (5) Chromatic aberration only + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_chroma_only + ENDCG + } + + // (6) Distort only + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag_distort_only + ENDCG + } + } + FallBack off +} diff --git a/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta new file mode 100644 index 0000000..e89bc32 --- /dev/null +++ b/Assets/Cinematic Effects/LensAberrations/Resources/LensAberrations.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 136ab50fe2b9ad64d9c22adc3668abb7 +timeCreated: 1454583143 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur.meta b/Assets/Cinematic Effects/MotionBlur.meta new file mode 100644 index 0000000..ada916f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 22361d70f5bd34f35be82589af855289 +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins.meta b/Assets/Cinematic Effects/MotionBlur/Plugins.meta new file mode 100644 index 0000000..ee24b52 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 01c03782ff2da4717ae56fc9d4e95223 +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll new file mode 100644 index 0000000..8ce8d8c Binary files /dev/null and b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll differ diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta new file mode 100644 index 0000000..ed556df --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotion.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: f4044b596510fe5489da703d40efc52b +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs new file mode 100644 index 0000000..7e391fe --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs @@ -0,0 +1,1167 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif +#if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 +#define UNITY_PRE_5_3 +#endif + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using UnityEngine; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif +using UnityEngine.Serialization; + +namespace AmplifyMotion +{ + public enum Quality + { + Mobile = 0, + Standard = 1, + Standard_SM3 = 2, + SoftEdge_SM3 = 3 + } +} + +[RequireComponent( typeof( Camera ) )] +[AddComponentMenu( "" )] +public class AmplifyMotionEffectBase : MonoBehaviour +{ + public AmplifyMotion.Quality QualityLevel = AmplifyMotion.Quality.Standard; + public bool AutoRegisterObjs = true; + public Camera[] OverlayCameras = new Camera[ 0 ]; + public LayerMask CullingMask = ~0; + public int QualitySteps = 1; + public float MotionScale = 3.0f; + public float CameraMotionMult = 1.0f; + public float MinVelocity = 1.0f; + public float MaxVelocity = 10.0f; + public float DepthThreshold = 0.001f; + [FormerlySerializedAs( "workerThreads" )] public int WorkerThreads = 0; + public bool SystemThreadPool = false; + public bool ForceCPUOnly = false; + public bool DebugMode = false; + + // For compatibility + [Obsolete( "workerThreads is deprecated, please use WorkerThreads instead." )] + public int workerThreads { get { return WorkerThreads; } set { WorkerThreads = value; } } + + private Camera m_camera; + private bool m_starting = true; + + private int m_width, m_height; + private RenderTexture m_motionRT; +#if UNITY_4 + private Texture m_dummyTex; +#endif + private Material m_blurMaterial; + private Material m_solidVectorsMaterial; + private Material m_skinnedVectorsMaterial; + private Material m_clothVectorsMaterial; + private Material m_reprojectionMaterial; + private Material m_combineMaterial; + private Material m_dilationMaterial; + private Material m_depthMaterial; + private Material m_debugMaterial; + + internal Material SolidVectorsMaterial { get { return m_solidVectorsMaterial; } } + internal Material SkinnedVectorsMaterial { get { return m_skinnedVectorsMaterial; } } + internal Material ClothVectorsMaterial { get { return m_clothVectorsMaterial; } } + + internal RenderTexture MotionRenderTexture { get { return m_motionRT; } } + +#if TRIAL + private Texture2D m_watermark; +#endif + + private Dictionary m_linkedCameras = new Dictionary(); + public Dictionary LinkedCameras { get { return m_linkedCameras; } } + internal Camera[] m_linkedCameraKeys = null; + internal AmplifyMotionCamera[] m_linkedCameraValues = null; + internal bool m_linkedCamerasChanged = true; + + private AmplifyMotionPostProcess m_currentPostProcess = null; + + private int m_globalObjectId = 1; + + private float m_deltaTime; + private float m_fixedDeltaTime; + + private float m_motionScaleNorm; + private float m_fixedMotionScaleNorm; + + internal float MotionScaleNorm { get { return m_motionScaleNorm; } } + internal float FixedMotionScaleNorm { get { return m_fixedMotionScaleNorm; } } + + private AmplifyMotion.Quality m_qualityLevel; + + private AmplifyMotionCamera m_baseCamera = null; + public AmplifyMotionCamera BaseCamera { get { return m_baseCamera; } } + + private AmplifyMotion.WorkerThreadPool m_workerThreadPool = null; + internal AmplifyMotion.WorkerThreadPool WorkerPool { get { return m_workerThreadPool; } } + + // GLOBAL OBJECT MANAGEMENT + public static Dictionary m_activeObjects = new Dictionary(); + public static Dictionary m_activeCameras = new Dictionary(); + + private static bool m_isD3D = false; + public static bool IsD3D { get { return m_isD3D; } } + + private bool m_canUseGPU = false; + public bool CanUseGPU { get { return m_canUseGPU; } } + +#if !UNITY_4 + private const CameraEvent m_updateCBEvent = CameraEvent.BeforeImageEffectsOpaque; + private CommandBuffer m_updateCB = null; + + private const CameraEvent m_fixedUpdateCBEvent = CameraEvent.BeforeImageEffectsOpaque; + private CommandBuffer m_fixedUpdateCB = null; + + private const CameraEvent m_renderCBEvent = CameraEvent.BeforeImageEffects; + private CommandBuffer m_renderCB = null; +#endif + + private static bool m_ignoreMotionScaleWarning = false; + public static bool IgnoreMotionScaleWarning { get { return m_ignoreMotionScaleWarning; } } + + private static AmplifyMotionEffectBase m_firstInstance = null; + public static AmplifyMotionEffectBase FirstInstance { get { return m_firstInstance; } } + public static AmplifyMotionEffectBase Instance { get { return m_firstInstance; } } + + void Awake() + { + if ( m_firstInstance == null ) + m_firstInstance = this; + + m_isD3D = SystemInfo.graphicsDeviceVersion.StartsWith( "Direct3D" ); + m_globalObjectId = 1; + m_width = m_height = 0; + + if ( ForceCPUOnly ) + m_canUseGPU = false; + else + { + #if !UNITY_4 + bool hasRTs = SystemInfo.supportsRenderTextures; + bool hasSM3 = ( SystemInfo.graphicsShaderLevel >= 30 ); + bool hasRHalfTex = SystemInfo.SupportsTextureFormat( TextureFormat.RHalf ); + bool hasRGHalfTex = SystemInfo.SupportsTextureFormat( TextureFormat.RGHalf ); + bool hasARGBHalfTex = SystemInfo.SupportsTextureFormat( TextureFormat.RGBAHalf ); + bool hasARGBFloatRT = SystemInfo.SupportsRenderTextureFormat( RenderTextureFormat.ARGBFloat ); + + m_canUseGPU = hasRTs && hasSM3 && hasRHalfTex && hasRGHalfTex && hasARGBHalfTex && hasARGBFloatRT; + #endif + } + } + + internal void ResetObjectId() + { + m_globalObjectId = 1; + } + + internal int GenerateObjectId( GameObject obj ) + { + // id = 0, static objs + // id = 255, excluded objs + + if ( obj.isStatic ) + return 0; // same as background + + m_globalObjectId++; + + // TEMPORARY FIX: wrap around; may cause artifacts on id collision of nearby objs + if ( m_globalObjectId > 254 ) + m_globalObjectId = 1; + + return m_globalObjectId; + } + + void SafeDestroyMaterial( ref Material mat ) + { + if ( mat != null ) + { + DestroyImmediate( mat ); + mat = null; + } + } + + bool CheckMaterialAndShader( Material material, string name ) + { + bool ok = true; + if ( material == null || material.shader == null ) + { + Debug.LogWarning( "[AmplifyMotion] Error creating " + name + " material" ); + ok = false; + } + else if ( !material.shader.isSupported ) + { + Debug.LogWarning( "[AmplifyMotion] " + name + " shader not supported on this platform" ); + ok = false; + } + return ok; + } + + void DestroyMaterials() + { + SafeDestroyMaterial( ref m_blurMaterial ); + SafeDestroyMaterial( ref m_solidVectorsMaterial ); + SafeDestroyMaterial( ref m_skinnedVectorsMaterial ); + SafeDestroyMaterial( ref m_clothVectorsMaterial ); + SafeDestroyMaterial( ref m_reprojectionMaterial ); + SafeDestroyMaterial( ref m_combineMaterial ); + SafeDestroyMaterial( ref m_dilationMaterial ); + SafeDestroyMaterial( ref m_depthMaterial ); + SafeDestroyMaterial( ref m_debugMaterial ); + } + + bool CreateMaterials() + { + DestroyMaterials(); + + int shaderModel = ( SystemInfo.graphicsShaderLevel >= 30 ) ? 3 : 2; + + string blurShader = "Hidden/Amplify Motion/MotionBlurSM" + shaderModel; + string solidVectorsShader = "Hidden/Amplify Motion/SolidVectors"; + string skinnedVectorsShader = "Hidden/Amplify Motion/SkinnedVectors"; + string clothVectorsShader = "Hidden/Amplify Motion/ClothVectors"; + string reprojectionVectorsShader = "Hidden/Amplify Motion/ReprojectionVectors"; + string combineShader = "Hidden/Amplify Motion/Combine"; + string dilationShader = "Hidden/Amplify Motion/Dilation"; + string depthShader = "Hidden/Amplify Motion/Depth"; + string debugShader = "Hidden/Amplify Motion/Debug"; + + try + { + m_blurMaterial = new Material( Shader.Find( blurShader ) ) { hideFlags = HideFlags.DontSave }; + m_solidVectorsMaterial = new Material( Shader.Find( solidVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_skinnedVectorsMaterial = new Material( Shader.Find( skinnedVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_clothVectorsMaterial = new Material( Shader.Find( clothVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_reprojectionMaterial = new Material( Shader.Find( reprojectionVectorsShader ) ) { hideFlags = HideFlags.DontSave }; + m_combineMaterial = new Material( Shader.Find( combineShader ) ) { hideFlags = HideFlags.DontSave }; + m_dilationMaterial = new Material( Shader.Find( dilationShader ) ) { hideFlags = HideFlags.DontSave }; + m_depthMaterial = new Material( Shader.Find( depthShader ) ) { hideFlags = HideFlags.DontSave }; + m_debugMaterial = new Material( Shader.Find( debugShader ) ) { hideFlags = HideFlags.DontSave }; + } + catch ( Exception ) + { + } + + // even if we fail, we still need to know which one failed + bool ok = CheckMaterialAndShader( m_blurMaterial, blurShader ); + ok = ok && CheckMaterialAndShader( m_solidVectorsMaterial, solidVectorsShader ); + ok = ok && CheckMaterialAndShader( m_skinnedVectorsMaterial, skinnedVectorsShader ); + ok = ok && CheckMaterialAndShader( m_clothVectorsMaterial, clothVectorsShader ); + ok = ok && CheckMaterialAndShader( m_reprojectionMaterial, reprojectionVectorsShader ); + ok = ok && CheckMaterialAndShader( m_combineMaterial, combineShader ); + ok = ok && CheckMaterialAndShader( m_dilationMaterial, dilationShader ); + ok = ok && CheckMaterialAndShader( m_depthMaterial, depthShader ); + ok = ok && CheckMaterialAndShader( m_debugMaterial, debugShader ); + return ok; + } + + RenderTexture CreateRenderTexture( string name, int depth, RenderTextureFormat fmt, RenderTextureReadWrite rw, FilterMode fm ) + { + RenderTexture rt = new RenderTexture( m_width, m_height, depth, fmt, rw ); + rt.hideFlags = HideFlags.DontSave; + rt.name = name; + rt.wrapMode = TextureWrapMode.Clamp; + rt.filterMode = fm; + rt.Create(); + return rt; + } + + void SafeDestroyRenderTexture( ref RenderTexture rt ) + { + if ( rt != null ) + { + RenderTexture.active = null; + rt.Release(); + DestroyImmediate( rt ); + rt = null; + } + } + + void SafeDestroyTexture( ref Texture tex ) + { + if ( tex != null ) + { + DestroyImmediate( tex ); + tex = null; + } + } + + void DestroyRenderTextures() + { + RenderTexture.active = null; + + SafeDestroyRenderTexture( ref m_motionRT ); + + #if UNITY_4 + SafeDestroyTexture( ref m_dummyTex ); + if ( m_dummyTex != null ) + { + DestroyImmediate( m_dummyTex ); + m_dummyTex = null; + } + #endif + } + + void UpdateRenderTextures( bool qualityChanged ) + { + int screenWidth = Mathf.FloorToInt( m_camera.pixelWidth + 0.5f ); + int screenHeight = Mathf.FloorToInt( m_camera.pixelHeight + 0.5f ); + + if ( QualityLevel == AmplifyMotion.Quality.Mobile ) + { + screenWidth /= 2; + screenHeight /= 2; + } + + if ( m_width != screenWidth || m_height != screenHeight || qualityChanged ) + { + m_width = screenWidth; + m_height = screenHeight; + + DestroyRenderTextures(); + } + + if ( m_motionRT == null ) + m_motionRT = CreateRenderTexture( "AM-MotionVectors", 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear, FilterMode.Point ); + + #if UNITY_4 + if ( m_dummyTex == null ) + { + m_dummyTex = new Texture2D( 4, 4, TextureFormat.ARGB32, false, true ); + m_dummyTex.wrapMode = TextureWrapMode.Clamp; + m_dummyTex.hideFlags = HideFlags.DontSave; + } + #endif + } + + public bool CheckSupport() + { + if ( !SystemInfo.supportsImageEffects || !SystemInfo.supportsRenderTextures ) + { + Debug.LogError( "[AmplifyMotion] Initialization failed. This plugin requires support for Image Effects and Render Textures." ); + return false; + } + return true; + } + + void InitializeThreadPool() + { + if ( WorkerThreads <= 0 ) + WorkerThreads = Mathf.Max( Environment.ProcessorCount / 2, 1 ); // half of CPU threads; non-busy idle + + m_workerThreadPool = new AmplifyMotion.WorkerThreadPool(); + m_workerThreadPool.InitializeAsyncUpdateThreads( WorkerThreads, SystemThreadPool ); + } + + void ShutdownThreadPool() + { + if ( m_workerThreadPool != null ) + { + m_workerThreadPool.FinalizeAsyncUpdateThreads(); + m_workerThreadPool = null; + } + } + + void InitializeCommandBuffers() + { + #if !UNITY_4 + ShutdownCommandBuffers(); + + m_updateCB = new CommandBuffer(); + m_updateCB.name = "AmplifyMotion.Update"; + m_camera.AddCommandBuffer( m_updateCBEvent, m_updateCB ); + + m_fixedUpdateCB = new CommandBuffer(); + m_fixedUpdateCB.name = "AmplifyMotion.FixedUpdate"; + m_camera.AddCommandBuffer( m_fixedUpdateCBEvent, m_fixedUpdateCB ); + + m_renderCB = new CommandBuffer(); + m_renderCB.name = "AmplifyMotion.Render"; + m_camera.AddCommandBuffer( m_renderCBEvent, m_renderCB ); + + #endif + } + + void ShutdownCommandBuffers() + { + #if !UNITY_4 + if ( m_updateCB != null ) + { + m_camera.RemoveCommandBuffer( m_updateCBEvent, m_updateCB ); + m_updateCB.Release(); + m_updateCB = null; + } + if ( m_fixedUpdateCB != null ) + { + m_camera.RemoveCommandBuffer( m_fixedUpdateCBEvent, m_fixedUpdateCB ); + m_fixedUpdateCB.Release(); + m_fixedUpdateCB = null; + } + if ( m_renderCB != null ) + { + m_camera.RemoveCommandBuffer( m_renderCBEvent, m_renderCB ); + m_renderCB.Release(); + m_renderCB = null; + } + #endif + } + + void OnEnable() + { + m_camera = GetComponent(); + + if ( !CheckSupport() ) + { + enabled = false; + return; + } + + InitializeThreadPool(); + + m_starting = true; + + if ( !CreateMaterials() ) + { + Debug.LogError( "[AmplifyMotion] Failed loading or compiling necessary shaders. Please try reinstalling Amplify Motion or contact support@amplify.pt" ); + enabled = false; + return; + } + + if ( AutoRegisterObjs ) + UpdateActiveObjects(); + + InitializeCameras(); + InitializeCommandBuffers(); + + UpdateRenderTextures( true ); + + m_linkedCameras.TryGetValue( m_camera, out m_baseCamera ); + + if ( m_baseCamera == null ) + { + Debug.LogError( "[AmplifyMotion] Failed setting up Base Camera. Please contact support@amplify.pt" ); + enabled = false; + return; + } + if ( m_currentPostProcess != null ) + m_currentPostProcess.enabled = true; + + m_qualityLevel = QualityLevel; + } + + void OnDisable() + { + if ( m_currentPostProcess != null ) + m_currentPostProcess.enabled = false; + + ShutdownCommandBuffers(); + ShutdownThreadPool(); + } + + void Start() + { + UpdatePostProcess(); + +#if TRIAL + m_watermark = new Texture2D( 4, 4 ); + m_watermark.LoadImage( AmplifyMotion.Watermark.ImageData ); +#endif + } + + internal void RemoveCamera( Camera reference ) + { + m_linkedCameras.Remove( reference ); + } + + void OnDestroy() + { + AmplifyMotionCamera[] prevLinkedCams = m_linkedCameras.Values.ToArray(); + + foreach ( AmplifyMotionCamera cam in prevLinkedCams ) + { + if ( cam != null && cam.gameObject != gameObject ) + { + Camera actual = cam.GetComponent(); + if ( actual != null ) + actual.targetTexture = null; + DestroyImmediate( cam ); + } + } + + DestroyRenderTextures(); + DestroyMaterials(); +#if TRIAL + DestroyImmediate( m_watermark ); +#endif + } + + GameObject RecursiveFindCamera( GameObject obj, string auxCameraName ) + { + GameObject cam = null; + if ( obj.name == auxCameraName ) + cam = obj; + else + { + foreach ( Transform child in obj.transform ) + { + cam = RecursiveFindCamera( child.gameObject, auxCameraName ); + if ( cam != null ) + break; + } + } + return cam; + } + + void InitializeCameras() + { + List cleanOverlayCameras = new List( OverlayCameras.Length ); + for ( int i = 0; i < OverlayCameras.Length; i++ ) + { + if ( OverlayCameras[ i ] != null ) + cleanOverlayCameras.Add( OverlayCameras[ i ] ); + } + + Camera[] referenceCameras = new Camera[ cleanOverlayCameras.Count + 1 ]; + + referenceCameras[ 0 ] = m_camera; + for ( int i = 0; i < cleanOverlayCameras.Count; i++ ) + referenceCameras[ i + 1 ] = cleanOverlayCameras[ i ]; + + m_linkedCameras.Clear(); + + for ( int i = 0; i < referenceCameras.Length; i++ ) + { + Camera reference = referenceCameras[ i ]; + if ( !m_linkedCameras.ContainsKey( reference ) ) + { + AmplifyMotionCamera cam = reference.gameObject.GetComponent(); + if ( cam != null ) + { + cam.enabled = false; + cam.enabled = true; + } + else + cam = reference.gameObject.AddComponent(); + + cam.LinkTo( this, i > 0 ); + + m_linkedCameras.Add( reference, cam ); + m_linkedCamerasChanged = true; + } + } + } + + public void UpdateActiveCameras() + { + InitializeCameras(); + } + + internal static void RegisterCamera( AmplifyMotionCamera cam ) + { + m_activeCameras.Add( cam.GetComponent(), cam ); + foreach ( AmplifyMotionObjectBase obj in m_activeObjects.Values ) + obj.RegisterCamera( cam ); + } + + internal static void UnregisterCamera( AmplifyMotionCamera cam ) + { + foreach ( AmplifyMotionObjectBase obj in m_activeObjects.Values ) + obj.UnregisterCamera( cam ); + m_activeCameras.Remove( cam.GetComponent() ); + } + + public void UpdateActiveObjects() + { + GameObject[] gameObjs = FindObjectsOfType( typeof( GameObject ) ) as GameObject[]; + for ( int i = 0; i < gameObjs.Length; i++ ) + { + if ( !m_activeObjects.ContainsKey( gameObjs[ i ] ) ) + TryRegister( gameObjs[ i ], true ); + } + } + + internal static void RegisterObject( AmplifyMotionObjectBase obj ) + { + m_activeObjects.Add( obj.gameObject, obj ); + foreach ( AmplifyMotionCamera cam in m_activeCameras.Values ) + obj.RegisterCamera( cam ); + } + + internal static void UnregisterObject( AmplifyMotionObjectBase obj ) + { + foreach ( AmplifyMotionCamera cam in m_activeCameras.Values ) + obj.UnregisterCamera( cam ); + m_activeObjects.Remove( obj.gameObject ); + } + + internal static bool FindValidTag( Material[] materials ) + { + for ( int i = 0; i < materials.Length; i++ ) + { + Material mat = materials[ i ]; + if ( mat != null ) + { + string tag = mat.GetTag( "RenderType", false ); + if ( tag == "Opaque" || tag == "TransparentCutout" ) + #if UNITY_4 + return true; + #else + return !mat.IsKeywordEnabled( "_ALPHABLEND_ON" ) && !mat.IsKeywordEnabled( "_ALPHAPREMULTIPLY_ON" ); + #endif + } + } + return false; + } + + internal static bool CanRegister( GameObject gameObj, bool autoReg ) + { + // Ignore static objects + if ( gameObj.isStatic ) + return false; + + // Ignore invalid materials; Ignore static batches + Renderer renderer = gameObj.GetComponent(); + if ( renderer == null || renderer.sharedMaterials == null || renderer.isPartOfStaticBatch ) + return false; + + // Ignore disabled renderer + if ( !renderer.enabled ) + return false; + + // Ignore if visible only for shadows + #if !UNITY_4 + if ( renderer.shadowCastingMode == UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly ) + return false; + #endif + + if ( renderer.GetType() == typeof( SpriteRenderer ) ) + { + return false; + } + else + { + // Ignore unsupported RenderType + if ( !FindValidTag( renderer.sharedMaterials ) ) + return false; + + #if UNITY_4 + if ( renderer.GetType() == typeof( ClothRenderer ) ) + { + if ( gameObj.GetComponent().tearFactor != 0.0f ) + Debug.LogWarning( "[AmplifyMotion] Tearable cloth objects are not supported at this time. Ignoring cloth object \"" + renderer.name + "\"" ); + else + return true; + } + #endif + + // Only valid and supported renderers + Type type = renderer.GetType(); + if ( type == typeof( MeshRenderer ) || type == typeof( SkinnedMeshRenderer ) ) + { + return true; + } + + #if !UNITY_PRE_5_3 + if ( type == typeof( ParticleSystemRenderer ) && !autoReg ) + { + // Only supported ParticleSystem modes + ParticleSystemRenderMode mode = ( renderer as ParticleSystemRenderer ).renderMode; + return ( mode == ParticleSystemRenderMode.Mesh || mode == ParticleSystemRenderMode.Billboard ); + } + #endif + } + + return false; + } + + internal static void TryRegister( GameObject gameObj, bool autoReg ) + { + if ( CanRegister( gameObj, autoReg ) && gameObj.GetComponent() == null ) + { + AmplifyMotionObjectBase.ApplyToChildren = false; + gameObj.AddComponent(); + AmplifyMotionObjectBase.ApplyToChildren = true; + } + } + + internal static void TryUnregister( GameObject gameObj ) + { + AmplifyMotionObjectBase comp = gameObj.GetComponent(); + if ( comp != null ) + Destroy( comp ); + } + + public void Register( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + } + + public static void RegisterS( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + } + + public void RegisterRecursively( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + + foreach ( Transform child in gameObj.transform ) + RegisterRecursively( child.gameObject ); + } + + public static void RegisterRecursivelyS( GameObject gameObj ) + { + if ( !m_activeObjects.ContainsKey( gameObj ) ) + TryRegister( gameObj, false ); + + foreach ( Transform child in gameObj.transform ) + RegisterRecursivelyS( child.gameObject ); + } + + public void Unregister( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + } + + public static void UnregisterS( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + } + + public void UnregisterRecursively( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + + foreach ( Transform child in gameObj.transform ) + UnregisterRecursively( child.gameObject ); + } + + public static void UnregisterRecursivelyS( GameObject gameObj ) + { + if ( m_activeObjects.ContainsKey( gameObj ) ) + TryUnregister( gameObj ); + + foreach ( Transform child in gameObj.transform ) + UnregisterRecursivelyS( child.gameObject ); + } + + void UpdatePostProcess() + { + Camera highestReference = null; + float highestDepth = -float.MaxValue; + + if ( m_linkedCamerasChanged ) + UpdateLinkedCameras(); + + for ( int i = 0; i < m_linkedCameraKeys.Length; i++ ) + { + if ( m_linkedCameraKeys[ i ] != null && m_linkedCameraKeys[ i ].isActiveAndEnabled && m_linkedCameraKeys[ i ].depth > highestDepth ) + { + highestReference = m_linkedCameraKeys[ i ]; + highestDepth = m_linkedCameraKeys[ i ].depth; + } + } + + if ( m_currentPostProcess != null && m_currentPostProcess.gameObject != highestReference.gameObject ) + { + DestroyImmediate( m_currentPostProcess ); + m_currentPostProcess = null; + } + + if ( m_currentPostProcess == null && highestReference != null && highestReference != m_camera ) + { + AmplifyMotionPostProcess[] runtimes = gameObject.GetComponents(); + if ( runtimes != null && runtimes.Length > 0 ) + { + for ( int i = 0; i < runtimes.Length; i++ ) + DestroyImmediate( runtimes[ i ] ); + } + m_currentPostProcess = highestReference.gameObject.AddComponent(); + m_currentPostProcess.Instance = this; + } + } + + void LateUpdate() + { + if ( m_baseCamera.AutoStep ) + { + float delta = Application.isPlaying ? Time.deltaTime : Time.fixedDeltaTime; + float fixedDelta = Time.fixedDeltaTime; + + m_deltaTime = ( delta > float.Epsilon ) ? delta : m_deltaTime; + m_fixedDeltaTime = ( delta > float.Epsilon ) ? fixedDelta : m_fixedDeltaTime; + } + + QualitySteps = Mathf.Clamp( QualitySteps, 0, 16 ); + MotionScale = Mathf.Max( MotionScale, 0 ); + MinVelocity = Mathf.Min( MinVelocity, MaxVelocity ); + DepthThreshold = Mathf.Max( DepthThreshold, 0 ); + + UpdatePostProcess(); + } + + public void StopAutoStep() + { + foreach ( AmplifyMotionCamera cam in m_linkedCameras.Values ) + cam.StopAutoStep(); + } + + public void StartAutoStep() + { + foreach ( AmplifyMotionCamera cam in m_linkedCameras.Values ) + cam.StartAutoStep(); + } + + public void Step( float delta ) + { + m_deltaTime = delta; + m_fixedDeltaTime = delta; + foreach ( AmplifyMotionCamera cam in m_linkedCameras.Values ) + cam.Step(); + } + + void UpdateLinkedCameras() + { + Dictionary.KeyCollection keys = m_linkedCameras.Keys; + Dictionary.ValueCollection values = m_linkedCameras.Values; + + if ( m_linkedCameraKeys == null || keys.Count != m_linkedCameraKeys.Length ) + m_linkedCameraKeys = new Camera[ keys.Count ]; + + if ( m_linkedCameraValues == null || values.Count != m_linkedCameraValues.Length ) + m_linkedCameraValues = new AmplifyMotionCamera[ values.Count ]; + + keys.CopyTo( m_linkedCameraKeys, 0 ); + values.CopyTo( m_linkedCameraValues, 0 ); + + m_linkedCamerasChanged = false; + } + + void FixedUpdate() + { + if ( m_camera.enabled ) + { + if ( m_linkedCamerasChanged ) + UpdateLinkedCameras(); + + #if !UNITY_4 + m_fixedUpdateCB.Clear(); + #endif + + for ( int i = 0; i < m_linkedCameraValues.Length; i++ ) + { + if ( m_linkedCameraValues[ i ] != null && m_linkedCameraValues[ i ].isActiveAndEnabled ) + { + #if UNITY_4 + m_linkedCameraValues[ i ].FixedUpdateTransform(); + #else + m_linkedCameraValues[ i ].FixedUpdateTransform( m_fixedUpdateCB ); + #endif + } + } + } + } + + void OnPreRender() + { + if ( m_camera.enabled && ( Time.frameCount == 1 || Mathf.Abs( Time.deltaTime ) > float.Epsilon ) ) + { + if ( m_linkedCamerasChanged ) + UpdateLinkedCameras(); + + #if !UNITY_4 + m_updateCB.Clear(); + #endif + + for ( int i = 0; i < m_linkedCameraValues.Length; i++ ) + { + if ( m_linkedCameraValues[ i ] != null && m_linkedCameraValues[ i ].isActiveAndEnabled ) + { + #if UNITY_4 + m_linkedCameraValues[ i ].UpdateTransform(); + #else + m_linkedCameraValues[ i ].UpdateTransform( m_updateCB ); + #endif + } + } + } + } + +#if UNITY_4 + void RenderReprojectionVectors( RenderTexture destination, float scale ) + { + Shader.SetGlobalMatrix( "_AM_MATRIX_CURR_REPROJ", m_baseCamera.PrevViewProjMatrix * m_baseCamera.InvViewProjMatrix ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", scale ); + + Graphics.Blit( m_dummyTex, destination, m_reprojectionMaterial ); + } +#else + void RenderReprojectionVectors( CommandBuffer commandBuffer, RenderTexture destination, float scale ) + { + commandBuffer.SetGlobalMatrix( "_AM_MATRIX_CURR_REPROJ", m_baseCamera.PrevViewProjMatrix * m_baseCamera.InvViewProjMatrix ); + commandBuffer.SetGlobalFloat( "_AM_MOTION_SCALE", scale ); + + RenderTexture dummy = null; + commandBuffer.Blit( new RenderTargetIdentifier( dummy ), destination, m_reprojectionMaterial ); + } +#endif + + public static void DiscardContents( RenderTexture rtex ) + { + #if !( UNITY_WP8 || UNITY_WP8_1 || UNITY_WSA ) // why?.. + rtex.DiscardContents(); + #endif + } + + void OnPostRender() + { + bool qualityChanged = ( QualityLevel != m_qualityLevel ); + if ( qualityChanged ) + { + CreateMaterials(); + m_qualityLevel = QualityLevel; + } + UpdateRenderTextures( qualityChanged ); + + ResetObjectId(); + + #if UNITY_4 + RenderBuffer prevColor = Graphics.activeColorBuffer; + RenderBuffer prevDepth = Graphics.activeDepthBuffer; + #endif + bool cameraMotion = ( CameraMotionMult > float.Epsilon ); + bool clearColor = !cameraMotion || m_starting; + + float rcpDepthThreshold = ( DepthThreshold > float.Epsilon ) ? 1.0f / DepthThreshold : float.MaxValue; + + m_motionScaleNorm = ( m_deltaTime >= float.Epsilon ) ? MotionScale * ( 1.0f / m_deltaTime ) : 0; + m_fixedMotionScaleNorm = ( m_fixedDeltaTime >= float.Epsilon ) ? MotionScale * ( 1.0f / m_fixedDeltaTime ) : 0; + + float objectScale = !m_starting ? m_motionScaleNorm : 0; + float objectFixedScale = !m_starting ? m_fixedMotionScaleNorm : 0; + + DiscardContents( m_motionRT ); + + #if UNITY_4 + Graphics.SetRenderTarget( m_motionRT ); + GL.Clear( true, clearColor, Color.black ); + + Shader.SetGlobalFloat( "_AM_MIN_VELOCITY", MinVelocity ); + Shader.SetGlobalFloat( "_AM_MAX_VELOCITY", MaxVelocity ); + Shader.SetGlobalFloat( "_AM_RCP_TOTAL_VELOCITY", 1.0f / ( MaxVelocity - MinVelocity ) ); + Shader.SetGlobalVector( "_AM_DEPTH_THRESHOLD", new Vector2( DepthThreshold, rcpDepthThreshold ) ); + #else + m_updateCB.Clear(); + m_renderCB.Clear(); + + m_renderCB.SetGlobalFloat( "_AM_MIN_VELOCITY", MinVelocity ); + m_renderCB.SetGlobalFloat( "_AM_MAX_VELOCITY", MaxVelocity ); + m_renderCB.SetGlobalFloat( "_AM_RCP_TOTAL_VELOCITY", 1.0f / ( MaxVelocity - MinVelocity ) ); + m_renderCB.SetGlobalVector( "_AM_DEPTH_THRESHOLD", new Vector2( DepthThreshold, rcpDepthThreshold ) ); + + m_renderCB.SetRenderTarget( m_motionRT ); + m_renderCB.ClearRenderTarget( true, clearColor, Color.black ); + #endif + + if ( cameraMotion ) + { + float cameraMotionScaleNorm = ( m_deltaTime >= float.Epsilon ) ? MotionScale * CameraMotionMult * ( 1.0f / m_deltaTime ) : 0; + float cameraScale = !m_starting ? cameraMotionScaleNorm : 0; + + #if UNITY_4 + RenderReprojectionVectors( m_motionRT, cameraScale ); + #else + RenderReprojectionVectors( m_renderCB, m_motionRT, cameraScale ); + #endif + } + + #if UNITY_4 + m_baseCamera.RenderVectors( objectScale, objectFixedScale, QualityLevel ); + #else + // base camera + m_baseCamera.RenderVectors( m_renderCB, objectScale, objectFixedScale, QualityLevel ); + + // overlay cameras + for ( int i = 0; i < m_linkedCameraValues.Length; i++ ) + { + AmplifyMotionCamera cam = m_linkedCameraValues[ i ]; + if ( cam != null && cam.Overlay && cam.isActiveAndEnabled ) + m_linkedCameraValues[ i ].RenderVectors( m_renderCB, objectScale, objectFixedScale, QualityLevel ); + } + #endif + + m_starting = false; + + #if UNITY_4 + Graphics.SetRenderTarget( prevColor, prevDepth ); + #endif + } + + void ApplyMotionBlur( RenderTexture source, RenderTexture destination, Vector4 blurStep ) + { + bool mobile = ( QualityLevel == AmplifyMotion.Quality.Mobile ); + int pass = ( int ) QualityLevel; + + RenderTexture depthRT = null; + if ( mobile ) + { + depthRT = RenderTexture.GetTemporary( m_width, m_height, 0, RenderTextureFormat.ARGB32 ); + depthRT.name = "AM-DepthTemp"; + depthRT.wrapMode = TextureWrapMode.Clamp; + depthRT.filterMode = FilterMode.Point; + } + + RenderTexture combinedRT = RenderTexture.GetTemporary( m_width, m_height, 0, source.format ); + combinedRT.name = "AM-CombinedTemp"; + combinedRT.wrapMode = TextureWrapMode.Clamp; + combinedRT.filterMode = FilterMode.Point; + + DiscardContents( combinedRT ); + m_combineMaterial.SetTexture( "_MotionTex", m_motionRT ); + source.filterMode = FilterMode.Point; + Graphics.Blit( source, combinedRT, m_combineMaterial, 0 ); + + m_blurMaterial.SetTexture( "_MotionTex", m_motionRT ); + if ( mobile ) + { + Graphics.Blit( null, depthRT, m_depthMaterial, 0 ); + m_blurMaterial.SetTexture( "_DepthTex", depthRT ); + } + + if ( QualitySteps > 1 ) + { + RenderTexture temp = RenderTexture.GetTemporary( m_width, m_height, 0, source.format ); + temp.name = "AM-CombinedTemp2"; + temp.filterMode = FilterMode.Point; + + float step = 1.0f / QualitySteps; + float scale = 1.0f; + RenderTexture src = combinedRT; + RenderTexture dst = temp; + + for ( int i = 0; i < QualitySteps; i++ ) + { + if ( dst != destination ) + DiscardContents( dst ); + + m_blurMaterial.SetVector( "_AM_BLUR_STEP", blurStep * scale ); + Graphics.Blit( src, dst, m_blurMaterial, pass ); + + if ( i < QualitySteps - 2 ) + { + RenderTexture tmp = dst; + dst = src; + src = tmp; + } + else + { + src = dst; + dst = destination; + } + scale -= step; + } + + RenderTexture.ReleaseTemporary( temp ); + } + else + { + m_blurMaterial.SetVector( "_AM_BLUR_STEP", blurStep ); + Graphics.Blit( combinedRT, destination, m_blurMaterial, pass ); + } + + if ( mobile ) + { + // we need the full res here + m_combineMaterial.SetTexture( "_MotionTex", m_motionRT ); + Graphics.Blit( source, destination, m_combineMaterial, 1 ); + } + + RenderTexture.ReleaseTemporary( combinedRT ); + if ( depthRT != null ) + RenderTexture.ReleaseTemporary( depthRT ); + } + + void OnRenderImage( RenderTexture source, RenderTexture destination ) + { + if ( m_currentPostProcess == null ) + PostProcess( source, destination ); + else + Graphics.Blit( source, destination ); + } + + public void PostProcess( RenderTexture source, RenderTexture destination ) + { + Vector4 blurStep = Vector4.zero; + blurStep.x = MaxVelocity / 1000.0f; + blurStep.y = MaxVelocity / 1000.0f; + + RenderTexture dilatedRT = null; + if ( QualitySettings.antiAliasing > 1 ) + { + dilatedRT = RenderTexture.GetTemporary( m_width, m_height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear ); + dilatedRT.name = "AM-DilatedTemp"; + dilatedRT.filterMode = FilterMode.Point; + + m_dilationMaterial.SetTexture( "_MotionTex", m_motionRT ); + Graphics.Blit( m_motionRT, dilatedRT, m_dilationMaterial, 0 ); + m_dilationMaterial.SetTexture( "_MotionTex", dilatedRT ); + Graphics.Blit( dilatedRT, m_motionRT, m_dilationMaterial, 1 ); + } + + if ( DebugMode ) + { + m_debugMaterial.SetTexture( "_MotionTex", m_motionRT ); + Graphics.Blit( source, destination, m_debugMaterial ); + } + else + { + ApplyMotionBlur( source, destination, blurStep ); + } + + if ( dilatedRT != null ) + RenderTexture.ReleaseTemporary( dilatedRT ); + } + +#if TRIAL + void OnGUI() + { + GUI.DrawTexture( new Rect( 15, Screen.height - m_watermark.height - 12, m_watermark.width, m_watermark.height ), m_watermark ); + } +#endif + + //void OnGUI() + //{ + // GUI.color = Color.black; + // GUILayout.BeginHorizontal(); + // GUILayout.Space( 300 ); + // GUILayout.BeginVertical(); + // GUILayout.Label( "GPU / RT / SM3 => " + m_canUseGPU + " / " + SystemInfo.supportsRenderTextures + " / " + ( SystemInfo.graphicsShaderLevel >= 30 ) ); + // GUILayout.Label( "TEX.RHalf => " + SystemInfo.SupportsTextureFormat( TextureFormat.RHalf ) ); + // GUILayout.Label( "TEX.RGHalf => " + SystemInfo.SupportsTextureFormat( TextureFormat.RGHalf ) ); + // GUILayout.Label( "TEX.RGBAHalf => " + SystemInfo.SupportsTextureFormat( TextureFormat.RGBAHalf ) ); + // GUILayout.Label( "RT.RFloat => " + SystemInfo.SupportsRenderTextureFormat( RenderTextureFormat.RFloat ) ); + // GUILayout.Label( "RT.ARGBFloat => " + SystemInfo.SupportsRenderTextureFormat( RenderTextureFormat.ARGBFloat ) ); + // GUILayout.EndVertical(); + // GUILayout.EndHorizontal(); + //} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta new file mode 100644 index 0000000..fb79157 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8deec7bec0fc2284e96c09a92987d61f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs new file mode 100644 index 0000000..874c73f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs @@ -0,0 +1,318 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +[AddComponentMenu( "" )] +[RequireComponent( typeof( Camera ) )] +public class AmplifyMotionCamera : MonoBehaviour +{ + internal AmplifyMotionEffectBase Instance = null; + + internal Matrix4x4 PrevViewProjMatrix; + internal Matrix4x4 ViewProjMatrix; + internal Matrix4x4 InvViewProjMatrix; + + internal Matrix4x4 PrevViewProjMatrixRT; + internal Matrix4x4 ViewProjMatrixRT; + + internal Transform Transform; + + private bool m_linked = false; + private bool m_initialized = false; + private bool m_starting = true; + + private bool m_autoStep = true; + private bool m_step = false; + private bool m_overlay = false; + private Camera m_camera; + + public bool Initialized { get { return m_initialized; } } + public bool AutoStep { get { return m_autoStep; } } + public bool Overlay { get { return m_overlay; } } + public Camera Camera { get { return m_camera; } } + + private int m_prevFrameCount = 0; + + private HashSet m_affectedObjectsTable = new HashSet(); + private AmplifyMotionObjectBase[] m_affectedObjects = null; + private bool m_affectedObjectsChanged = true; + + public void RegisterObject( AmplifyMotionObjectBase obj ) + { + m_affectedObjectsTable.Add( obj ); + m_affectedObjectsChanged = true; + } + + public void UnregisterObject( AmplifyMotionObjectBase obj ) + { + m_affectedObjectsTable.Remove( obj ); + m_affectedObjectsChanged = true; + } + + void UpdateAffectedObjects() + { + if ( m_affectedObjects == null || m_affectedObjectsTable.Count != m_affectedObjects.Length ) + m_affectedObjects = new AmplifyMotionObjectBase[ m_affectedObjectsTable.Count ]; + + m_affectedObjectsTable.CopyTo( m_affectedObjects ); + + m_affectedObjectsChanged = false; + } + + public void LinkTo( AmplifyMotionEffectBase instance, bool overlay ) + { + Instance = instance; + + m_camera = GetComponent(); + m_camera.depthTextureMode |= DepthTextureMode.Depth; + + m_overlay = overlay; + m_linked = true; + } + + public void Initialize() + { + m_step = false; + UpdateMatrices(); + m_initialized = true; + } + + void Awake() + { + Transform = transform; + } + + void OnEnable() + { + AmplifyMotionEffectBase.RegisterCamera( this ); + } + + void OnDisable() + { + m_initialized = false; + AmplifyMotionEffectBase.UnregisterCamera( this ); + } + + void OnDestroy() + { + if ( Instance != null ) + Instance.RemoveCamera( m_camera ); + } + + public void StopAutoStep() + { + if ( m_autoStep ) + { + m_autoStep = false; + m_step = true; + } + } + + public void StartAutoStep() + { + m_autoStep = true; + } + + public void Step() + { + m_step = true; + } + + void Update() + { + if ( !m_linked || !Instance.isActiveAndEnabled ) + return; + + if ( !m_initialized ) + Initialize(); + + if ( ( m_camera.depthTextureMode & DepthTextureMode.Depth ) == 0 ) + m_camera.depthTextureMode |= DepthTextureMode.Depth; + } + + void UpdateMatrices() + { + if ( !m_starting ) + { + PrevViewProjMatrix = ViewProjMatrix; + PrevViewProjMatrixRT = ViewProjMatrixRT; + } + + Matrix4x4 view = m_camera.worldToCameraMatrix; + Matrix4x4 proj = GL.GetGPUProjectionMatrix( m_camera.projectionMatrix, false ); + ViewProjMatrix = proj * view; + InvViewProjMatrix = Matrix4x4.Inverse( ViewProjMatrix ); + + Matrix4x4 projRT = GL.GetGPUProjectionMatrix( m_camera.projectionMatrix, true ); + ViewProjMatrixRT = projRT * view; + + if ( m_starting ) + { + PrevViewProjMatrix = ViewProjMatrix; + PrevViewProjMatrixRT = ViewProjMatrixRT; + } + } + +#if UNITY_4 + public void FixedUpdateTransform() +#else + public void FixedUpdateTransform( CommandBuffer updateCB ) +#endif + { + if ( !m_initialized ) + Initialize(); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + { + if ( m_affectedObjects[ i ].FixedStep ) + { + #if UNITY_4 + m_affectedObjects[ i ].OnUpdateTransform( m_camera, m_starting ); + #else + m_affectedObjects[ i ].OnUpdateTransform( m_camera, updateCB, m_starting ); + #endif + } + } + } + +#if UNITY_4 + public void UpdateTransform() +#else + public void UpdateTransform( CommandBuffer updateCB ) +#endif + { + if ( !m_initialized ) + Initialize(); + + if ( Time.frameCount > m_prevFrameCount && ( m_autoStep || m_step ) ) + { + UpdateMatrices(); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + { + if ( !m_affectedObjects[ i ].FixedStep ) + { + #if UNITY_4 + m_affectedObjects[ i ].OnUpdateTransform( m_camera, m_starting ); + #else + m_affectedObjects[ i ].OnUpdateTransform( m_camera, updateCB, m_starting ); + #endif + + } + } + + m_starting = false; + m_step = false; + + m_prevFrameCount = Time.frameCount; + } + } + +#if UNITY_4 + public void RenderVectors( float scale, float fixedScale, AmplifyMotion.Quality quality ) +#else + public void RenderVectors( CommandBuffer renderCB, float scale, float fixedScale, AmplifyMotion.Quality quality ) +#endif + { + if ( !m_initialized ) + Initialize(); + + // For some reason Unity's own values weren't working correctly on Windows/OpenGL + float near = m_camera.nearClipPlane; + float far = m_camera.farClipPlane; + Vector4 zparam; + + if ( AmplifyMotionEffectBase.IsD3D ) + { + zparam.x = 1.0f - far / near; + zparam.y = far / near; + } + else + { + // OpenGL + zparam.x = ( 1.0f - far / near ) / 2.0f; + zparam.y = ( 1.0f + far / near ) / 2.0f; + } + + zparam.z = zparam.x / far; + zparam.w = zparam.y / far; + + Shader.SetGlobalVector( "_AM_ZBUFFER_PARAMS", zparam ); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + { + // don't render objects excluded via camera culling mask + if ( ( m_camera.cullingMask & ( 1 << m_affectedObjects[ i ].gameObject.layer ) ) != 0 ) + { + #if UNITY_4 + m_affectedObjects[ i ].OnRenderVectors( m_camera, m_affectedObjects[ i ].FixedStep ? fixedScale : scale, quality ); + #else + m_affectedObjects[ i ].OnRenderVectors( m_camera, renderCB, m_affectedObjects[ i ].FixedStep ? fixedScale : scale, quality ); + #endif + } + } + } + +#if UNITY_4 + void OnPostRender() + { + if ( !m_linked || !Instance.isActiveAndEnabled ) + return; + + if ( !m_initialized ) + Initialize(); + + if ( m_overlay ) + { + + RenderTexture prevRT = RenderTexture.active; + + Graphics.SetRenderTarget( Instance.MotionRenderTexture ); + RenderVectors( Instance.MotionScaleNorm, Instance.FixedMotionScaleNorm, Instance.QualityLevel ); + + RenderTexture.active = prevRT; + } + } +#endif + + void OnGUI() + { + if ( !Application.isEditor ) + return; + + if ( !m_linked || !Instance.isActiveAndEnabled ) + return; + + if ( !m_initialized ) + Initialize(); + + if ( m_affectedObjectsChanged ) + UpdateAffectedObjects(); + + for ( int i = 0; i < m_affectedObjects.Length; i++ ) + m_affectedObjects[ i ].OnRenderDebugHUD( m_camera ); + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta new file mode 100644 index 0000000..7cdf87b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionCamera.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 32f3679b48c5ac84f913fe16c3ffb43a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs new file mode 100644 index 0000000..8259f05 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs @@ -0,0 +1,13 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using UnityEngine; + +[RequireComponent( typeof( Camera ) )] +[AddComponentMenu( "Image Effects/Amplify Motion" )] +public class AmplifyMotionEffect : AmplifyMotionEffectBase +{ + public static new AmplifyMotionEffect FirstInstance { get { return ( AmplifyMotionEffect ) AmplifyMotionEffectBase.FirstInstance; } } + public static new AmplifyMotionEffect Instance { get { return ( AmplifyMotionEffect ) AmplifyMotionEffectBase.Instance; } } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta new file mode 100644 index 0000000..27f08b4 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionEffect.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 390397f02bff7644ab045efd81d0d720 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 0ea3c819440ae8346ae765cd2a7d95cc, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs new file mode 100644 index 0000000..9005615 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs @@ -0,0 +1,10 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using UnityEngine; + +[AddComponentMenu( "Image Effects/Amplify Motion Object" )] +public class AmplifyMotionObject : AmplifyMotionObjectBase +{ +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta new file mode 100644 index 0000000..ddf4146 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObject.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3be5e33915e952b4cac8186b1a6f8f3f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: be11958c9498dd048baecca8002f8212, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs new file mode 100644 index 0000000..3b7b98f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs @@ -0,0 +1,371 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif +#if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 +#define UNITY_PRE_5_3 +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ + +public enum ObjectType +{ + None, + Solid, + Skinned, + Cloth, +#if !UNITY_PRE_5_3 + Particle +#endif +} + +[Serializable] +internal abstract class MotionState +{ + protected struct MaterialDesc + { + public Material material; + #if !UNITY_4 + public MaterialPropertyBlock propertyBlock; + #endif + public bool coverage; + public bool cutoff; + } + + public const int AsyncUpdateTimeout = 100; + + protected bool m_error; + protected bool m_initialized; + protected Transform m_transform; + + protected AmplifyMotionCamera m_owner; + protected AmplifyMotionObjectBase m_obj; + + public AmplifyMotionCamera Owner { get { return m_owner; } } + public bool Initialized { get { return m_initialized; } } + public bool Error { get { return m_error; } } + + public MotionState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + { + m_error = false; + m_initialized = false; + + m_owner = owner; + m_obj = obj; + m_transform = obj.transform; + } + + internal virtual void Initialize() { m_initialized = true; } + internal virtual void Shutdown() {} + + internal virtual void AsyncUpdate() {} +#if UNITY_4 + internal abstract void UpdateTransform( bool starting ); + internal virtual void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) {} +#else + internal abstract void UpdateTransform( CommandBuffer updateCB, bool starting ); + internal virtual void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) {} +#endif + internal virtual void RenderDebugHUD() {} + + private static HashSet m_materialWarnings = new HashSet(); + + protected MaterialDesc[] ProcessSharedMaterials( Material[] mats ) + { + MaterialDesc[] matsDesc = new MaterialDesc [ mats.Length ]; + for ( int i = 0; i < mats.Length; i++ ) + { + matsDesc[ i ].material = mats[ i ]; + bool legacyCoverage = ( mats[ i ].GetTag( "RenderType", false ) == "TransparentCutout" ); + #if UNITY_4 + bool isCoverage = legacyCoverage; + matsDesc[ i ].coverage = mats[ i ].HasProperty( "_MainTex" ) && isCoverage; + #else + bool isCoverage = legacyCoverage || mats[ i ].IsKeywordEnabled( "_ALPHATEST_ON" ); + matsDesc[ i ].propertyBlock = new MaterialPropertyBlock(); + matsDesc[ i ].coverage = mats[ i ].HasProperty( "_MainTex" ) && isCoverage; + #endif + matsDesc[ i ].cutoff = mats[ i ].HasProperty( "_Cutoff" ); + + if ( isCoverage && !matsDesc[ i ].coverage && !m_materialWarnings.Contains( matsDesc[ i ].material ) ) + { + Debug.LogWarning( "[AmplifyMotion] TransparentCutout material \"" + matsDesc[ i ].material.name + "\" {" + matsDesc[ i ].material.shader.name + "} not using _MainTex standard property." ); + m_materialWarnings.Add( matsDesc[ i ].material ); + } + } + return matsDesc; + } + + internal static bool VectorChanged( Vector3 a, Vector3 b ) + { + return Vector3.SqrMagnitude( a - b ) > 0.0f; + } + + internal static bool RotationChanged( Quaternion a, Quaternion b ) + { + Vector4 diff = new Vector4( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); + return Vector4.SqrMagnitude( diff ) > 0.0f; + } + + internal static void MulPoint4x4_XYZW( ref Vector4 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x = mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03 * vec.w; + result.y = mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13 * vec.w; + result.z = mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23 * vec.w; + result.w = mat.m30 * vec.x + mat.m31 * vec.y + mat.m32 * vec.z + mat.m33 * vec.w; + } + + internal static void MulPoint3x4_XYZ( ref Vector3 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x = mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03; + result.y = mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13; + result.z = mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23; + } + + internal static void MulPoint3x4_XYZW( ref Vector3 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x = mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03 * vec.w; + result.y = mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13 * vec.w; + result.z = mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23 * vec.w; + } + + internal static void MulAddPoint3x4_XYZW( ref Vector3 result, ref Matrix4x4 mat, Vector4 vec ) + { + result.x += mat.m00 * vec.x + mat.m01 * vec.y + mat.m02 * vec.z + mat.m03 * vec.w; + result.y += mat.m10 * vec.x + mat.m11 * vec.y + mat.m12 * vec.z + mat.m13 * vec.w; + result.z += mat.m20 * vec.x + mat.m21 * vec.y + mat.m22 * vec.z + mat.m23 * vec.w; + } +} +} + +[AddComponentMenu( "" )] +public class AmplifyMotionObjectBase : MonoBehaviour +{ + public enum MinMaxCurveState + { + Scalar = 0, + Curve = 1, + TwoCurves = 2, + TwoScalars = 3 + } + + internal static bool ApplyToChildren = true; + [SerializeField] private bool m_applyToChildren = ApplyToChildren; + + private AmplifyMotion.ObjectType m_type = AmplifyMotion.ObjectType.None; + private Dictionary m_states = new Dictionary(); + + private bool m_fixedStep = false; + private int m_objectId = 0; + + internal bool FixedStep { get { return m_fixedStep; } } + internal int ObjectId { get { return m_objectId; } } + + public AmplifyMotion.ObjectType Type { get { return m_type; } } + + internal void RegisterCamera( AmplifyMotionCamera camera ) + { + Camera actual = camera.GetComponent(); + if ( ( actual.cullingMask & ( 1 << gameObject.layer ) ) != 0 && !m_states.ContainsKey( actual ) ) + { + AmplifyMotion.MotionState state = null; + switch ( m_type ) + { + case AmplifyMotion.ObjectType.Solid: + state = new AmplifyMotion.SolidState( camera, this ); break; + case AmplifyMotion.ObjectType.Skinned: + state = new AmplifyMotion.SkinnedState( camera, this ); break; + case AmplifyMotion.ObjectType.Cloth: + state = new AmplifyMotion.ClothState( camera, this ); break; + #if !UNITY_PRE_5_3 + case AmplifyMotion.ObjectType.Particle: + state = new AmplifyMotion.ParticleState( camera, this ); break; + #endif + default: + throw new Exception( "[AmplifyMotion] Invalid object type." ); + } + + camera.RegisterObject( this ); + + m_states.Add( actual, state ); + } + } + + internal void UnregisterCamera( AmplifyMotionCamera camera ) + { + AmplifyMotion.MotionState state; + Camera actual = camera.GetComponent(); + if ( m_states.TryGetValue( actual, out state ) ) + { + camera.UnregisterObject( this ); + + if ( m_states.TryGetValue( actual, out state ) ) + state.Shutdown(); + + m_states.Remove( actual ); + } + } + + bool InitializeType() + { + Renderer renderer = GetComponent(); + if ( AmplifyMotionEffectBase.CanRegister( gameObject, false ) ) + { + #if !UNITY_PRE_5_3 + ParticleSystem particleRenderer = GetComponent(); + if ( particleRenderer != null ) + { + m_type = AmplifyMotion.ObjectType.Particle; + AmplifyMotionEffectBase.RegisterObject( this ); + } + else + #endif + if ( renderer != null ) + { + // At this point, Renderer is guaranteed to be one of the following + if ( renderer.GetType() == typeof( MeshRenderer ) ) + m_type = AmplifyMotion.ObjectType.Solid; + #if UNITY_4 + else if ( renderer.GetType() == typeof( ClothRenderer ) ) + m_type = AmplifyMotion.ObjectType.Cloth; + #endif + else if ( renderer.GetType() == typeof( SkinnedMeshRenderer ) ) + { + #if !UNITY_4 + if ( GetComponent() != null ) + m_type = AmplifyMotion.ObjectType.Cloth; + else + #endif + m_type = AmplifyMotion.ObjectType.Skinned; + } + + AmplifyMotionEffectBase.RegisterObject( this ); + } + } + + // No renderer? disable it, it is here just for adding children + return ( renderer != null ); + } + + void OnEnable() + { + bool valid = InitializeType(); + if ( valid ) + { + if ( m_type == AmplifyMotion.ObjectType.Cloth ) + { + #if UNITY_4 + m_fixedStep = true; + #else + m_fixedStep = false; + #endif + } + else if ( m_type == AmplifyMotion.ObjectType.Solid ) + { + Rigidbody rigidbody = GetComponent(); + if ( rigidbody != null && rigidbody.interpolation == RigidbodyInterpolation.None && !rigidbody.isKinematic ) + m_fixedStep = true; + } + } + + if ( m_applyToChildren ) + { + foreach ( Transform child in gameObject.transform ) + AmplifyMotionEffectBase.RegisterRecursivelyS( child.gameObject ); + } + + if ( !valid ) + enabled = false; + } + + void OnDisable() + { + AmplifyMotionEffectBase.UnregisterObject( this ); + } + + void TryInitializeStates() + { + var enumerator = m_states.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + AmplifyMotion.MotionState state = enumerator.Current.Value; + if ( state.Owner.Initialized && !state.Error && !state.Initialized ) + state.Initialize(); + } + } + + void Start() + { + if ( AmplifyMotionEffectBase.Instance != null ) + TryInitializeStates(); + } + + void Update() + { + if ( AmplifyMotionEffectBase.Instance != null ) + TryInitializeStates(); + } + +#if UNITY_4 + internal void OnUpdateTransform( Camera camera, bool starting ) +#else + internal void OnUpdateTransform( Camera camera, CommandBuffer updateCB, bool starting ) +#endif + { + AmplifyMotion.MotionState state; + if ( m_states.TryGetValue( camera, out state ) ) + { + if ( !state.Error ) + { + #if UNITY_4 + state.UpdateTransform( starting ); + #else + state.UpdateTransform( updateCB, starting ); + #endif + } + } + } + +#if UNITY_4 + internal void OnRenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) +#else + internal void OnRenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) +#endif + { + AmplifyMotion.MotionState state; + if ( m_states.TryGetValue( camera, out state ) ) + { + if ( !state.Error ) + { + #if UNITY_4 + state.RenderVectors( camera, scale, quality ); + #else + state.RenderVectors( camera, renderCB, scale, quality ); + #endif + } + } + } + + internal void OnRenderDebugHUD( Camera camera ) + { + AmplifyMotion.MotionState state; + if ( m_states.TryGetValue( camera, out state ) ) + { + if ( !state.Error ) + state.RenderDebugHUD(); + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta new file mode 100644 index 0000000..839dc99 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionObjectBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d700ac4720013ea408722e2fce137691 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs new file mode 100644 index 0000000..0ff752b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs @@ -0,0 +1,20 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using System.Collections.Generic; +using UnityEngine; + +[AddComponentMenu( "" )] +[RequireComponent( typeof( Camera ) )] +sealed public class AmplifyMotionPostProcess : MonoBehaviour +{ + private AmplifyMotionEffectBase m_instance = null; + public AmplifyMotionEffectBase Instance { get { return m_instance; } set { m_instance = value; } } + + void OnRenderImage( RenderTexture source, RenderTexture destination ) + { + if ( m_instance != null ) + m_instance.PostProcess( source, destination ); + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta new file mode 100644 index 0000000..e47b0ca --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/AmplifyMotionPostProcess.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 14fbfa86b7161f344b463004a203fcea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs new file mode 100644 index 0000000..43cda78 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs @@ -0,0 +1,293 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections.Generic; +using System.Threading; +using UnityEngine; +using UnityEngine.Profiling; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ +internal class ClothState : AmplifyMotion.MotionState +{ +#if UNITY_4 + private InteractiveCloth m_cloth; +#else + private Cloth m_cloth; +#endif + private Renderer m_renderer; + + public Matrix4x4 m_prevLocalToWorld; + public Matrix4x4 m_currLocalToWorld; + + private int m_targetVertexCount; + private int[] m_targetRemap; + private Vector3[] m_prevVertices; + private Vector3[] m_currVertices; + + private Mesh m_clonedMesh; + + private MaterialDesc[] m_sharedMaterials; + + private bool m_starting; + private bool m_wasVisible; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public ClothState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + #if UNITY_4 + m_cloth = m_obj.GetComponent(); + #else + m_cloth = m_obj.GetComponent(); + #endif + } + + internal override void Initialize() + { + if ( m_cloth.vertices == null ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Invalid " + m_cloth.GetType().Name + " vertices in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + #if UNITY_4 + Mesh clothMesh = m_cloth.mesh; + #else + SkinnedMeshRenderer skinnedRenderer = m_cloth.gameObject.GetComponent(); + Mesh clothMesh = skinnedRenderer.sharedMesh; + #endif + + if ( clothMesh == null || clothMesh.vertices == null || clothMesh.triangles == null ) + { + Debug.LogError( "[AmplifyMotion] Invalid Mesh on Cloth-enabled object " + m_obj.name ); + m_error = true; + return; + } + + base.Initialize(); + + m_renderer = m_cloth.gameObject.GetComponent(); + + int meshVertexCount = clothMesh.vertexCount; + Vector3[] meshVertices = clothMesh.vertices; + Vector2[] meshTexcoords = clothMesh.uv; + int[] meshTriangles = clothMesh.triangles; + + m_targetRemap = new int[ meshVertexCount ]; + + if ( m_cloth.vertices.Length == clothMesh.vertices.Length ) + { + for ( int i = 0; i < meshVertexCount; i++ ) + m_targetRemap[ i ] = i; + } + else + { + // a) May contains duplicated verts, optimization/cleanup is required + Dictionary dict = new Dictionary(); + int original, vertexCount = 0; + + for ( int i = 0; i < meshVertexCount; i++ ) + { + if ( dict.TryGetValue( meshVertices[ i ], out original ) ) + m_targetRemap[ i ] = original; + else + { + m_targetRemap[ i ] = vertexCount; + dict.Add( meshVertices[ i ], vertexCount++ ); + } + } + + // b) Tear is activated, creates extra verts (NOT SUPPORTED, POOL OF VERTS USED, NO ACCESS TO TRIANGLES) + } + + m_targetVertexCount = meshVertexCount; + m_prevVertices = new Vector3[ m_targetVertexCount ]; + m_currVertices = new Vector3[ m_targetVertexCount ]; + + m_clonedMesh = new Mesh(); + m_clonedMesh.vertices = meshVertices; + m_clonedMesh.normals = meshVertices; + m_clonedMesh.uv = meshTexcoords; + m_clonedMesh.triangles = meshTriangles; + + m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials ); + + m_wasVisible = false; + } + + internal override void Shutdown() + { + Mesh.Destroy( m_clonedMesh ); + } + +#if UNITY_4 + internal override void UpdateTransform( bool starting ) +#else + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) +#endif + { + if ( !m_initialized ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Cloth.Update" ); + + if ( !starting && m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + bool isVisible = m_renderer.isVisible; + if ( !m_error && ( isVisible || starting ) ) + { + if ( !starting && m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_targetVertexCount ); + } + + #if UNITY_4 + m_currLocalToWorld = Matrix4x4.identity; + #else + m_currLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one ); + #endif + + if ( starting || !m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_starting = starting; + m_wasVisible = isVisible; + + Profiler.EndSample(); + } + +#if UNITY_4 + internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Cloth.Render" ); + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Vector3[] clothVertices = m_cloth.vertices; + for ( int i = 0; i < m_targetVertexCount; i++ ) + m_currVertices[ i ] = clothVertices[ m_targetRemap[ i ] ]; + + if ( m_starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_targetVertexCount ); + + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + m_owner.Instance.ClothVectorsMaterial.mainTexture = matDesc.material.mainTexture; + if ( matDesc.cutoff ) + m_owner.Instance.ClothVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + if ( m_owner.Instance.ClothVectorsMaterial.SetPass( pass ) ) + { + #if UNITY_4 + Graphics.DrawMeshNow( m_clonedMesh, Matrix4x4.identity, i ); + #else + Graphics.DrawMeshNow( m_clonedMesh, m_currLocalToWorld, i ); + #endif + } + } + + Profiler.EndSample(); + } + } +#else + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Cloth.Render" ); + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Vector3[] clothVertices = m_cloth.vertices; + for ( int i = 0; i < m_targetVertexCount; i++ ) + m_currVertices[ i ] = clothVertices[ m_targetRemap[ i ] ]; + + if ( m_starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_targetVertexCount ); + + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + renderCB.DrawMesh( m_clonedMesh, m_currLocalToWorld, m_owner.Instance.ClothVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + + Profiler.EndSample(); + } + } +#endif +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta new file mode 100644 index 0000000..2f84319 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ClothState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ee21680ad49e16d47baa6b281c4511d1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta new file mode 100644 index 0000000..b1069c5 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7dfaf547c29f54b01bfc82b484a511b6 +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs new file mode 100644 index 0000000..77703b9 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs @@ -0,0 +1,92 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyMotion +{ + public class About : EditorWindow + { + private const string AboutImagePath = "AmplifyMotion/Textures/About.png"; + private Vector2 m_scrollPosition = Vector2.zero; + private Texture2D m_aboutImage; + + [MenuItem( "Window/Amplify Motion/About...", false, 20 )] + static void Init() + { + About window = ( About ) EditorWindow.GetWindow( typeof( About ) , true , "About Amplify Motion" ); + window.minSize = new Vector2( 502, 258 ); + window.maxSize = new Vector2( 502, 258 ); + window.Show(); + } + + public void OnFocus() + { + string[] guids = AssetDatabase.FindAssets( "About t:Texture" ); + string asset = ""; + + foreach ( string guid in guids ) + { + string path = AssetDatabase.GUIDToAssetPath( guid ); + if ( path.EndsWith( AboutImagePath ) ) + { + asset = path; + break; + } + } + + if ( !string.IsNullOrEmpty( asset ) ) + { + TextureImporter importer = AssetImporter.GetAtPath( asset ) as TextureImporter; + + if ( importer.textureType != TextureImporterType.GUI ) + { + importer.textureType = TextureImporterType.GUI; + AssetDatabase.ImportAsset( asset ); + } + + m_aboutImage = AssetDatabase.LoadAssetAtPath( asset, typeof( Texture2D ) ) as Texture2D; + } + else + Debug.LogWarning( "[AmplifyMotion] About image not found at " + AboutImagePath ); + } + + public void OnGUI() + { + m_scrollPosition = GUILayout.BeginScrollView( m_scrollPosition ); + + GUILayout.BeginVertical(); + + GUILayout.Space( 10 ); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Box( m_aboutImage, GUIStyle.none ); + + if ( Event.current.type == EventType.MouseUp && GUILayoutUtility.GetLastRect().Contains( Event.current.mousePosition ) ) + Application.OpenURL( "http://www.amplify.pt" ); + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUIStyle labelStyle = new GUIStyle( EditorStyles.label ); + labelStyle.alignment = TextAnchor.MiddleCenter; + labelStyle.wordWrap = true; + + GUILayout.Space( 10 ); + + GUILayout.Label( "\nAmplify Motion " + VersionInfo.StaticToString() + " - Full-scene Motion Blur", labelStyle, GUILayout.ExpandWidth( true ) ); + + GUILayout.Space( 6 ); + + GUILayout.Label( "\nCopyright (c) Amplify Creations, Lda. All rights reserved.\n", labelStyle, GUILayout.ExpandWidth( true ) ); + + GUILayout.EndVertical(); + + GUILayout.EndScrollView(); + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta new file mode 100644 index 0000000..b103acc --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/About.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8702049a56e8d69438a372d2291d93f6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll new file mode 100644 index 0000000..a95f1aa Binary files /dev/null and b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll differ diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll.meta new file mode 100644 index 0000000..6a26777 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionEditor.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 1a9ae1fa1f8b6324483523d4e0a5fabb +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 0 + settings: {} + Editor: + enabled: 1 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs new file mode 100644 index 0000000..f73e079 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs @@ -0,0 +1,14 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using UnityEngine; +using UnityEditor; +using System.Collections; +using UnityEditor.Callbacks; +using UnityEditorInternal; + +[InitializeOnLoad] +[CustomEditor( typeof( AmplifyMotionObject ) )] +public class AmplifyMotionObjectEditor : AmplifyMotionObjectEditorBase +{ +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta new file mode 100644 index 0000000..8b33994 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fa9cf487ac20ad844953ae6d9746f058 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs new file mode 100644 index 0000000..eb704c1 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs @@ -0,0 +1,13 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Reflection; +using UnityEditor.Callbacks; +using UnityEditorInternal; + +public class AmplifyMotionObjectEditorBase : Editor +{ +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta new file mode 100644 index 0000000..3746cc4 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/AmplifyMotionObjectEditorBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 74f699bbe74c7f1469a9a32862bbaa9a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta new file mode 100644 index 0000000..84b80f5 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: fe82cb816e6564133af86bf31fc695dd +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png new file mode 100644 index 0000000..d77d47c Binary files /dev/null and b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png differ diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta new file mode 100644 index 0000000..a21974e --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/effect-icon.png.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: 0ea3c819440ae8346ae765cd2a7d95cc +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -2 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif new file mode 100644 index 0000000..5971775 Binary files /dev/null and b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif differ diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta new file mode 100644 index 0000000..89933bb --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Editor/Resources/object-icon.tif.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: be11958c9498dd048baecca8002f8212 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs new file mode 100644 index 0000000..d8b48d7 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs @@ -0,0 +1,327 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif +#if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 +#define UNITY_PRE_5_3 +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; + +#if !UNITY_PRE_5_3 +using UnityEngine.Rendering; + +namespace AmplifyMotion +{ +internal class ParticleState : AmplifyMotion.MotionState +{ + public class Particle + { + public int refCount; + public Matrix4x4 prevLocalToWorld; + public Matrix4x4 currLocalToWorld; + } + + public ParticleSystem m_particleSystem; + public ParticleSystemRenderer m_renderer; + + private Mesh m_mesh; + + private ParticleSystem.RotationOverLifetimeModule rotationOverLifetime; + private ParticleSystem.RotationBySpeedModule rotationBySpeed; + + private ParticleSystem.Particle[] m_particles; + private Dictionary m_particleDict; + private List m_listToRemove; + private Stack m_particleStack; + private int m_capacity; + + private MaterialDesc[] m_sharedMaterials; + + public bool m_moved = false; + private bool m_wasVisible; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public ParticleState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + m_particleSystem = m_obj.GetComponent(); + m_renderer = m_particleSystem.GetComponent(); + rotationOverLifetime = m_particleSystem.rotationOverLifetime; + rotationBySpeed = m_particleSystem.rotationBySpeed; + } + + private Mesh CreateBillboardMesh() + { + int[] tris = new int[ 6 ] { 0, 1, 2, 2, 3, 0 }; + + Vector3[] vertices = new Vector3[ 4 ] { + new Vector3( -0.5f, -0.5f, 0 ), + new Vector3( 0.5f, -0.5f, 0 ), + new Vector3( 0.5f, 0.5f, 0 ), + new Vector3( -0.5f, 0.5f, 0 ) }; + + Vector2[] uv = new Vector2[ 4 ] { + new Vector2( 0, 0 ), + new Vector2( 1, 0 ), + new Vector2( 1, 1 ), + new Vector2( 0, 1 ) }; + + Mesh mesh = new Mesh(); + mesh.vertices = vertices; + mesh.uv = uv; + mesh.triangles = tris; + return mesh; + } + + private Mesh CreateStretchedBillboardMesh() + { + int[] tris = new int[ 6 ] { 0, 1, 2, 2, 3, 0 }; + + Vector3[] vertices = new Vector3[ 4 ] { + new Vector3( 0, -0.5f, -1.0f ), + new Vector3( 0, -0.5f, 0.0f ), + new Vector3( 0, 0.5f, 0.0f ), + new Vector3( 0, 0.5f, -1.0f ) + }; + + Vector2[] uv = new Vector2[ 4 ] { + new Vector2( 1, 1 ), + new Vector2( 0, 1 ), + new Vector2( 0, 0 ), + new Vector2( 1, 0 ) }; + + Mesh mesh = new Mesh(); + mesh.vertices = vertices; + mesh.uv = uv; + mesh.triangles = tris; + return mesh; + } + + internal override void Initialize() + { + if ( m_renderer == null ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Missing/Invalid Particle Renderer in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + base.Initialize(); + + if ( m_renderer.renderMode == ParticleSystemRenderMode.Mesh ) + m_mesh = m_renderer.mesh; + else if ( m_renderer.renderMode == ParticleSystemRenderMode.Stretch ) + m_mesh = CreateStretchedBillboardMesh(); + else + m_mesh = CreateBillboardMesh(); + + m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials ); + + m_capacity = m_particleSystem.maxParticles; + + m_particleDict = new Dictionary( m_capacity ); + m_particles = new ParticleSystem.Particle[ m_capacity ]; + m_listToRemove = new List( m_capacity ); + m_particleStack = new Stack( m_capacity ); + + for ( int k = 0; k < m_capacity; k++ ) + m_particleStack.Push( new Particle() ); + + m_wasVisible = false; + } + + void RemoveDeadParticles() + { + m_listToRemove.Clear(); + + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + KeyValuePair pair = enumerator.Current; + + if ( pair.Value.refCount <= 0 ) + { + m_particleStack.Push( pair.Value ); + if(!m_listToRemove.Contains(pair.Key)) + m_listToRemove.Add( pair.Key ); + } + else + pair.Value.refCount = 0; + } + + for ( int i = 0; i < m_listToRemove.Count; i++ ) + m_particleDict.Remove( m_listToRemove[ i ] ); + } + + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) + { + if ( !m_initialized || m_capacity != m_particleSystem.maxParticles ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Particle.Update" ); + + if ( !starting && m_wasVisible ) + { + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + Particle particle = enumerator.Current.Value; + particle.prevLocalToWorld = particle.currLocalToWorld; + } + } + + m_moved = true; + + int numAlive = m_particleSystem.GetParticles( m_particles ); + + Matrix4x4 transformLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one ); + + bool separateAxes = ( rotationOverLifetime.enabled && rotationOverLifetime.separateAxes ) || + ( rotationBySpeed.enabled && rotationBySpeed.separateAxes ); + + for ( int i = 0; i < numAlive; i++ ) + { + uint seed = m_particles[ i ].randomSeed; + Particle particle; + + bool justSpawned = false; + if ( !m_particleDict.TryGetValue( seed, out particle ) && m_particleStack.Count > 0 ) + { + m_particleDict[ seed ] = particle = m_particleStack.Pop(); + justSpawned = true; + } + + if ( particle == null ) + continue; + + float currentSize = m_particles[ i ].GetCurrentSize( m_particleSystem ); + Vector3 size = new Vector3( currentSize, currentSize, currentSize ); + + Matrix4x4 particleCurrLocalToWorld; + if ( m_renderer.renderMode == ParticleSystemRenderMode.Mesh ) + { + Quaternion rotation; + if ( separateAxes ) + rotation = Quaternion.Euler( m_particles[ i ].rotation3D ); + else + rotation = Quaternion.AngleAxis( m_particles[ i ].rotation, m_particles[ i ].axisOfRotation ); + + Matrix4x4 particleMatrix = Matrix4x4.TRS( m_particles[ i ].position, rotation, size ); + + if ( m_particleSystem.simulationSpace == ParticleSystemSimulationSpace.World ) + particleCurrLocalToWorld = particleMatrix; + else + particleCurrLocalToWorld = transformLocalToWorld * particleMatrix; + } + else if ( m_renderer.renderMode == ParticleSystemRenderMode.Billboard ) + { + if ( m_particleSystem.simulationSpace == ParticleSystemSimulationSpace.Local ) + m_particles[ i ].position = transformLocalToWorld.MultiplyPoint( m_particles[ i ].position ); + + Quaternion rotation; + if ( separateAxes ) + rotation = Quaternion.Euler( -m_particles[ i ].rotation3D.x, -m_particles[ i ].rotation3D.y, m_particles[ i ].rotation3D.z ); + else + rotation = Quaternion.AngleAxis( m_particles[ i ].rotation, Vector3.back ); + + particleCurrLocalToWorld = Matrix4x4.TRS( m_particles[ i ].position, m_owner.Transform.rotation * rotation, size ); + } + else + { + // unsupported + particleCurrLocalToWorld = Matrix4x4.identity; + } + + particle.refCount = 1; + particle.currLocalToWorld = particleCurrLocalToWorld; + if ( justSpawned ) + particle.prevLocalToWorld = particle.currLocalToWorld; + } + + if ( starting || !m_wasVisible ) + { + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + Particle particle = enumerator.Current.Value; + particle.prevLocalToWorld = particle.currLocalToWorld; + } + } + + RemoveDeadParticles(); + + m_wasVisible = m_renderer.isVisible; + + Profiler.EndSample(); + } + + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + Profiler.BeginSample( "Particle.Render" ); + + // TODO: batch + + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + if ( !mask || ( mask && m_moved ) ) + { + const float rcp255 = 1 / 255.0f; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + var enumerator = m_particleDict.GetEnumerator(); + while ( enumerator.MoveNext() ) + { + KeyValuePair pair = enumerator.Current; + + Matrix4x4 prevModelViewProj = m_owner.PrevViewProjMatrixRT * pair.Value.prevLocalToWorld; + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + + renderCB.DrawMesh( m_mesh, pair.Value.currLocalToWorld, m_owner.Instance.SolidVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + } + } + } + + Profiler.EndSample(); + } +} +} + +#endif diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta new file mode 100644 index 0000000..4b9eb3a --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/ParticleState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9f0d513b4e0749b4d9367ab62c348623 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta new file mode 100644 index 0000000..cbe33a9 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c11944833b1df48bdbdad6a591d010cf +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs new file mode 100644 index 0000000..4b456f3 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs @@ -0,0 +1,64 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using UnityEngine; + +namespace AmplifyMotion +{ + [Serializable] + public class VersionInfo + { + public const byte Major = 1; + public const byte Minor = 7; + public const byte Release = 1; + + private static string StageSuffix = "_dev001"; + + #if TRIAL + private static string TrialSuffix = " Trial"; + #else + private static string TrialSuffix = ""; + #endif + + public static string StaticToString() + { + return string.Format( "{0}.{1}.{2}", Major, Minor, Release ) + StageSuffix + TrialSuffix; + } + + public override string ToString() + { + return string.Format( "{0}.{1}.{2}", m_major, m_minor, m_release ) + StageSuffix + TrialSuffix; + } + + public int Number { get { return m_major * 100 + m_minor * 10 + m_release; } } + + [SerializeField] private int m_major; + [SerializeField] private int m_minor; + [SerializeField] private int m_release; + + VersionInfo() + { + m_major = Major; + m_minor = Minor; + m_release = Release; + } + + VersionInfo( byte major, byte minor, byte release ) + { + m_major = major; + m_minor = minor; + m_release = release; + } + + public static VersionInfo Current() + { + return new VersionInfo( Major, Minor, Release ); + } + + public static bool Matches( VersionInfo version ) + { + return ( Major == version.m_major ) && ( Minor == version.m_minor ) && ( Release == version.m_release ); + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta new file mode 100644 index 0000000..19e5f71 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/Runtime/VersionInfo.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 69a9dd9acbcff9d45acbf435fddd6110 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs new file mode 100644 index 0000000..bf231cd --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs @@ -0,0 +1,848 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; +using UnityEngine; +using UnityEngine.Profiling; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ +internal class SkinnedState : AmplifyMotion.MotionState +{ + private SkinnedMeshRenderer m_renderer; + + private int m_boneCount; + private Transform[] m_boneTransforms; + private Matrix4x4[] m_bones; + + private int m_weightCount; + private int[] m_boneIndices; + private float[] m_boneWeights; + + private int m_vertexCount; + private Vector4[] m_baseVertices; + private Vector3[] m_prevVertices; + private Vector3[] m_currVertices; + +#if !UNITY_4 + private int m_gpuBoneTexWidth; + private int m_gpuBoneTexHeight; + private int m_gpuVertexTexWidth; + private int m_gpuVertexTexHeight; + private Material m_gpuSkinDeformMat; + private Color[] m_gpuBoneData; + private Texture2D m_gpuBones; + private Texture2D m_gpuBoneIndices; + private Texture2D[] m_gpuBaseVertices; + private RenderTexture m_gpuPrevVertices; + private RenderTexture m_gpuCurrVertices; +#endif + + private Mesh m_clonedMesh; + private Matrix4x4 m_worldToLocalMatrix; + private Matrix4x4 m_prevLocalToWorld; + private Matrix4x4 m_currLocalToWorld; + + private MaterialDesc[] m_sharedMaterials; + + private ManualResetEvent m_asyncUpdateSignal = null; + private bool m_asyncUpdateTriggered = false; + + private bool m_starting; + private bool m_wasVisible; + private bool m_useFallback; + private bool m_useGPU = false; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public SkinnedState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + m_renderer = m_obj.GetComponent(); + } + + internal override void Initialize() + { + if ( !m_renderer.sharedMesh.isReadable ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Read/Write Import Setting disabled in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + // find out if we're forced to use the fallback path + Transform[] bones = m_renderer.bones; + m_useFallback = ( bones == null || bones.Length == 0 ); + + if ( !m_useFallback ) + m_useGPU = m_owner.Instance.CanUseGPU; // use GPU, if allowed + + base.Initialize(); + + m_vertexCount = m_renderer.sharedMesh.vertexCount; + m_prevVertices = new Vector3[ m_vertexCount ]; + m_currVertices = new Vector3[ m_vertexCount ]; + m_clonedMesh = new Mesh(); + + if ( !m_useFallback ) + { + if ( m_renderer.quality == SkinQuality.Auto ) + m_weightCount = ( int ) QualitySettings.blendWeights; + else + m_weightCount = ( int ) m_renderer.quality; + + m_boneTransforms = m_renderer.bones; + m_boneCount = m_renderer.bones.Length; + m_bones = new Matrix4x4[ m_boneCount ]; + + Vector4[] baseVertices = new Vector4[ m_vertexCount * m_weightCount ]; + int[] boneIndices = new int[ m_vertexCount * m_weightCount ]; + float[] boneWeights = ( m_weightCount > 1 ) ? new float[ m_vertexCount * m_weightCount ] : null; + + if ( m_weightCount == 1 ) + InitializeBone1( baseVertices, boneIndices ); + else if ( m_weightCount == 2 ) + InitializeBone2( baseVertices, boneIndices, boneWeights ); + else + InitializeBone4( baseVertices, boneIndices, boneWeights ); + + m_baseVertices = baseVertices; + m_boneIndices = boneIndices; + m_boneWeights = boneWeights; + + Mesh skinnedMesh = m_renderer.sharedMesh; + + m_clonedMesh.vertices = skinnedMesh.vertices; + m_clonedMesh.normals = skinnedMesh.vertices; + m_clonedMesh.uv = skinnedMesh.uv; + m_clonedMesh.subMeshCount = skinnedMesh.subMeshCount; + for ( int i = 0; i < skinnedMesh.subMeshCount; i++ ) + m_clonedMesh.SetTriangles( skinnedMesh.GetTriangles( i ), i ); + + #if !UNITY_4 + if ( m_useGPU ) + { + if ( !InitializeGPUSkinDeform() ) + { + // fallback + Debug.LogWarning( "[AmplifyMotion] Failed initializing GPU skin deform for object " + m_obj.name + ". Falling back to CPU path." ); + m_useGPU = false; + } + else + { + // release unnecessary data + m_boneIndices = null; + m_boneWeights = null; + + m_baseVertices = null; + m_prevVertices = null; + m_currVertices = null; + } + } + #endif + + if ( !m_useGPU ) + { + m_asyncUpdateSignal = new ManualResetEvent( false ); + m_asyncUpdateTriggered = false; + } + } + + m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials ); + + m_wasVisible = false; + } + + internal override void Shutdown() + { + if ( !m_useFallback && !m_useGPU ) + WaitForAsyncUpdate(); + + #if !UNITY_4 + if ( m_useGPU ) + ShutdownGPUSkinDeform(); + #endif + + if ( m_clonedMesh != null ) + { + Mesh.Destroy( m_clonedMesh ); + m_clonedMesh = null; + } + + m_boneTransforms = null; + m_bones = null; + m_boneIndices = null; + m_boneWeights = null; + m_baseVertices = null; + m_prevVertices = null; + m_currVertices = null; + m_sharedMaterials = null; + } + +#if !UNITY_4 + private bool InitializeGPUSkinDeform() + { + bool succeeded = true; + try + { + m_gpuBoneTexWidth = Mathf.NextPowerOfTwo( m_boneCount ); + m_gpuBoneTexHeight = 4; + m_gpuVertexTexWidth = Mathf.NextPowerOfTwo( Mathf.CeilToInt( Mathf.Sqrt( m_vertexCount ) ) ); + m_gpuVertexTexHeight = Mathf.NextPowerOfTwo( Mathf.CeilToInt( m_vertexCount / ( float ) m_gpuVertexTexWidth ) ); + + // gpu skin deform material + m_gpuSkinDeformMat = new Material( Shader.Find( "Hidden/Amplify Motion/GPUSkinDeform" ) ) { hideFlags = HideFlags.DontSave }; + + // bone matrix texture + m_gpuBones = new Texture2D( m_gpuBoneTexWidth, m_gpuBoneTexHeight, TextureFormat.RGBAFloat, false, true ); + m_gpuBones.hideFlags = HideFlags.DontSave; + m_gpuBones.name = "AM-" + m_obj.name + "-Bones"; + m_gpuBones.filterMode = FilterMode.Point; + + m_gpuBoneData = new Color[ m_gpuBoneTexWidth * m_gpuBoneTexHeight ]; + + UpdateBonesGPU(); + + // vertex bone index/weight textures + TextureFormat boneIDWFormat = TextureFormat.RHalf; + boneIDWFormat = ( m_weightCount == 2 ) ? TextureFormat.RGHalf : boneIDWFormat; + boneIDWFormat = ( m_weightCount == 4 ) ? TextureFormat.RGBAHalf : boneIDWFormat; + + m_gpuBoneIndices = new Texture2D( m_gpuVertexTexWidth, m_gpuVertexTexHeight, boneIDWFormat, false, true ); + m_gpuBoneIndices.hideFlags = HideFlags.DontSave; + m_gpuBoneIndices.name = "AM-" + m_obj.name + "-Bones"; + m_gpuBoneIndices.filterMode = FilterMode.Point; + m_gpuBoneIndices.wrapMode = TextureWrapMode.Clamp; + + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + Color[] boneIndices = new Color[ m_gpuVertexTexWidth * m_gpuVertexTexHeight ]; + + for ( int v = 0; v < m_vertexCount; v++ ) + { + int x = v % m_gpuVertexTexWidth; + int y = v / m_gpuVertexTexWidth; + int offset = y * m_gpuVertexTexWidth + x; + + BoneWeight boneWeight = meshBoneWeights[ v ]; + boneIndices[ offset ] = new Vector4( boneWeight.boneIndex0, boneWeight.boneIndex1, boneWeight.boneIndex2, boneWeight.boneIndex3 ); + } + m_gpuBoneIndices.SetPixels( boneIndices ); + m_gpuBoneIndices.Apply(); + + // base vertex textures + m_gpuBaseVertices = new Texture2D[ m_weightCount ]; + for ( int w = 0; w < m_weightCount; w++ ) + { + m_gpuBaseVertices[ w ] = new Texture2D( m_gpuVertexTexWidth, m_gpuVertexTexHeight, TextureFormat.RGBAFloat, false, true ); + m_gpuBaseVertices[ w ].hideFlags = HideFlags.DontSave; + m_gpuBaseVertices[ w ].name = "AM-" + m_obj.name + "-BaseVerts"; + m_gpuBaseVertices[ w ].filterMode = FilterMode.Point; + } + + List baseVertices = new List( m_weightCount ); + for ( int w = 0; w < m_weightCount; w++ ) + baseVertices.Add( new Color[ m_gpuVertexTexWidth * m_gpuVertexTexHeight ] ); + + for ( int v = 0; v < m_vertexCount; v++ ) + { + int x = v % m_gpuVertexTexWidth; + int y = v / m_gpuVertexTexWidth; + int offset = y * m_gpuVertexTexWidth + x; + + for ( int w = 0; w < m_weightCount; w++ ) + baseVertices[ w ][ offset ] = m_baseVertices[ v * m_weightCount + w ]; + } + for ( int w = 0; w < m_weightCount; w++ ) + { + m_gpuBaseVertices[ w ].SetPixels( baseVertices[ w ] ); + m_gpuBaseVertices[ w ].Apply(); + } + + // create output/target vertex render textures + m_gpuPrevVertices = new RenderTexture( m_gpuVertexTexWidth, m_gpuVertexTexHeight, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear ); + m_gpuPrevVertices.hideFlags = HideFlags.DontSave; + m_gpuPrevVertices.name = "AM-" + m_obj.name + "-PrevVerts"; + m_gpuPrevVertices.filterMode = FilterMode.Point; + m_gpuPrevVertices.wrapMode = TextureWrapMode.Clamp; + m_gpuPrevVertices.Create(); + + m_gpuCurrVertices = new RenderTexture( m_gpuVertexTexWidth, m_gpuVertexTexHeight, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear ); + m_gpuCurrVertices.hideFlags = HideFlags.DontSave; + m_gpuCurrVertices.name = "AM-" + m_obj.name + "-CurrVerts"; + m_gpuCurrVertices.filterMode = FilterMode.Point; + m_gpuCurrVertices.wrapMode = TextureWrapMode.Clamp; + m_gpuCurrVertices.Create(); + + // assign local material constants + m_gpuSkinDeformMat.SetTexture( "_AM_BONE_TEX", m_gpuBones ); + m_gpuSkinDeformMat.SetTexture( "_AM_BONE_INDEX_TEX", m_gpuBoneIndices ); + for ( int w = 0; w < m_weightCount; w++ ) + m_gpuSkinDeformMat.SetTexture( "_AM_BASE_VERTEX" + w + "_TEX", m_gpuBaseVertices[ w ] ); + + // assign global shader constants + Vector4 boneTexelSize = new Vector4( 1.0f / m_gpuBoneTexWidth, 1.0f / m_gpuBoneTexHeight, m_gpuBoneTexWidth, m_gpuBoneTexHeight ); + Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight ); + + m_gpuSkinDeformMat.SetVector( "_AM_BONE_TEXEL_SIZE", boneTexelSize ); + m_gpuSkinDeformMat.SetVector( "_AM_BONE_TEXEL_HALFSIZE", boneTexelSize * 0.5f ); + m_gpuSkinDeformMat.SetVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize ); + m_gpuSkinDeformMat.SetVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f ); + + // assign vertex x/y offsets packed into second uv channel + Vector2[] indexCoords = new Vector2[ m_vertexCount ]; + for ( int v = 0; v < m_vertexCount; v++ ) + { + int x = v % m_gpuVertexTexWidth; + int y = v / m_gpuVertexTexWidth; + float x_norm = ( x / ( float ) m_gpuVertexTexWidth ) + vertexTexelSize.x * 0.5f; + float y_norm = ( y / ( float ) m_gpuVertexTexHeight ) + vertexTexelSize.y * 0.5f; + indexCoords[ v ] = new Vector2( x_norm, y_norm ); + } + m_clonedMesh.uv2 = indexCoords; + } + catch ( Exception ) + { + succeeded = false; + } + return succeeded; + } + + private void ShutdownGPUSkinDeform() + { + if ( m_gpuSkinDeformMat != null ) + { + Material.DestroyImmediate( m_gpuSkinDeformMat ); + m_gpuSkinDeformMat = null; + } + + m_gpuBoneData = null; + + if ( m_gpuBones != null ) + { + Texture2D.DestroyImmediate( m_gpuBones ); + m_gpuBones = null; + } + + if ( m_gpuBoneIndices != null ) + { + Texture2D.DestroyImmediate( m_gpuBoneIndices ); + m_gpuBoneIndices = null; + } + + if ( m_gpuBaseVertices != null ) + { + for ( int i = 0; i < m_gpuBaseVertices.Length; i++ ) + Texture2D.DestroyImmediate( m_gpuBaseVertices[ i ] ); + m_gpuBaseVertices = null; + } + + if ( m_gpuPrevVertices != null ) + { + RenderTexture.active = null; + m_gpuPrevVertices.Release(); + RenderTexture.DestroyImmediate( m_gpuPrevVertices ); + m_gpuPrevVertices = null; + } + + if ( m_gpuCurrVertices != null ) + { + RenderTexture.active = null; + m_gpuCurrVertices.Release(); + RenderTexture.DestroyImmediate( m_gpuCurrVertices ); + m_gpuCurrVertices = null; + } + } + + private void UpdateBonesGPU() + { + for ( int b = 0; b < m_boneCount; b++ ) + { + for ( int r = 0; r < m_gpuBoneTexHeight; r++ ) + m_gpuBoneData[ r * m_gpuBoneTexWidth + b ] = m_bones[ b ].GetRow( r ); + } + m_gpuBones.SetPixels( m_gpuBoneData ); + m_gpuBones.Apply(); + } + + private void UpdateVerticesGPU( CommandBuffer updateCB, bool starting ) + { + if ( !starting && m_wasVisible ) + { + AmplifyMotionEffectBase.DiscardContents( m_gpuPrevVertices ); + updateCB.Blit( new RenderTargetIdentifier( m_gpuCurrVertices ), m_gpuPrevVertices ); + } + + updateCB.SetGlobalMatrix( "_AM_WORLD_TO_LOCAL_MATRIX", m_worldToLocalMatrix ); + + AmplifyMotionEffectBase.DiscardContents( m_gpuCurrVertices ); + RenderTexture dummy = null; + updateCB.Blit( new RenderTargetIdentifier( dummy ), m_gpuCurrVertices, m_gpuSkinDeformMat, Mathf.Min( m_weightCount - 1, 2 ) ); + + if ( starting || !m_wasVisible ) + { + AmplifyMotionEffectBase.DiscardContents( m_gpuPrevVertices ); + updateCB.Blit( new RenderTargetIdentifier( m_gpuCurrVertices ), m_gpuPrevVertices ); + } + } +#endif + + private void UpdateBones() + { + for ( int b = 0; b < m_boneCount; b++ ) + m_bones[ b ] = ( m_boneTransforms[ b ] != null ) ? m_boneTransforms[ b ].localToWorldMatrix : Matrix4x4.identity; + + m_worldToLocalMatrix = m_transform.worldToLocalMatrix; + + #if !UNITY_4 + if ( m_useGPU ) + { + Profiler.BeginSample( "UpdateBonesGPU" ); + UpdateBonesGPU(); + Profiler.EndSample(); + } + #endif + } + + private void UpdateVerticesFallback( bool starting ) + { + if ( !starting && m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + + m_renderer.BakeMesh( m_clonedMesh ); + + Array.Copy( m_clonedMesh.vertices, m_currVertices, m_vertexCount ); + + if ( starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + } + + private void AsyncUpdateVertices( bool starting ) + { + if ( !starting && m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + + for ( int i = 0; i < m_boneCount; i++ ) + m_bones[ i ] = m_worldToLocalMatrix * m_bones[ i ]; + + if ( m_weightCount == 1 ) + UpdateVerticesBone1(); + else if ( m_weightCount == 2 ) + UpdateVerticesBone2(); + else + UpdateVerticesBone4(); + + if ( starting || !m_wasVisible ) + Array.Copy( m_currVertices, m_prevVertices, m_vertexCount ); + } + + private void InitializeBone1( Vector4[] baseVertices, int[] boneIndices ) + { + Vector3[] meshVertices = m_renderer.sharedMesh.vertices; + Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes; + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * m_weightCount; + + int bone0 = boneIndices[ offset0 ] = meshBoneWeights[ i ].boneIndex0; + Vector3 baseVertex0 = meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] ); + + baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, 1.0f ); + } + } + + private void InitializeBone2( Vector4[] baseVertices, int[] boneIndices, float[] boneWeights ) + { + Vector3[] meshVertices = m_renderer.sharedMesh.vertices; + Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes; + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * m_weightCount; + int offset1 = offset0 + 1; + + BoneWeight boneWeight = meshBoneWeights[ i ]; + int bone0 = boneIndices[ offset0 ] = boneWeight.boneIndex0; + int bone1 = boneIndices[ offset1 ] = boneWeight.boneIndex1; + + float weight0 = boneWeight.weight0; + float weight1 = boneWeight.weight1; + + float rcpSum = 1.0f / ( weight0 + weight1 ); + boneWeights[ offset0 ] = weight0 = weight0 * rcpSum; + boneWeights[ offset1 ] = weight1 = weight1 * rcpSum; + + Vector3 baseVertex0 = weight0 * meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex1 = weight1 * meshBindPoses[ bone1 ].MultiplyPoint3x4( meshVertices[ i ] ); + + baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, weight0 ); + baseVertices[ offset1 ] = new Vector4( baseVertex1.x, baseVertex1.y, baseVertex1.z, weight1 ); + } + } + + private void InitializeBone4( Vector4[] baseVertices, int[] boneIndices, float[] boneWeights ) + { + Vector3[] meshVertices = m_renderer.sharedMesh.vertices; + Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes; + BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights; + + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * m_weightCount; + int offset1 = offset0 + 1; + int offset2 = offset0 + 2; + int offset3 = offset0 + 3; + + BoneWeight boneWeight = meshBoneWeights[ i ]; + int bone0 = boneIndices[ offset0 ] = boneWeight.boneIndex0; + int bone1 = boneIndices[ offset1 ] = boneWeight.boneIndex1; + int bone2 = boneIndices[ offset2 ] = boneWeight.boneIndex2; + int bone3 = boneIndices[ offset3 ] = boneWeight.boneIndex3; + + float weight0 = boneWeights[ offset0 ] = boneWeight.weight0; + float weight1 = boneWeights[ offset1 ] = boneWeight.weight1; + float weight2 = boneWeights[ offset2 ] = boneWeight.weight2; + float weight3 = boneWeights[ offset3 ] = boneWeight.weight3; + + Vector3 baseVertex0 = weight0 * meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex1 = weight1 * meshBindPoses[ bone1 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex2 = weight2 * meshBindPoses[ bone2 ].MultiplyPoint3x4( meshVertices[ i ] ); + Vector3 baseVertex3 = weight3 * meshBindPoses[ bone3 ].MultiplyPoint3x4( meshVertices[ i ] ); + + baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, weight0 ); + baseVertices[ offset1 ] = new Vector4( baseVertex1.x, baseVertex1.y, baseVertex1.z, weight1 ); + baseVertices[ offset2 ] = new Vector4( baseVertex2.x, baseVertex2.y, baseVertex2.z, weight2 ); + baseVertices[ offset3 ] = new Vector4( baseVertex3.x, baseVertex3.y, baseVertex3.z, weight3 ); + } + } + + private void UpdateVerticesBone1() + { + for ( int i = 0; i < m_vertexCount; i++ ) + MulPoint3x4_XYZ( ref m_currVertices[ i ], ref m_bones[ m_boneIndices[ i ] ], m_baseVertices[ i ] ); + } + + private void UpdateVerticesBone2() + { + Vector3 deformedVertex = Vector3.zero; + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * 2; + int offset1 = offset0 + 1; + + int b0 = m_boneIndices[ offset0 ]; + int b1 = m_boneIndices[ offset1 ]; + float weight1 = m_boneWeights[ offset1 ]; + + MulPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b0 ], m_baseVertices[ offset0 ] ); + if ( weight1 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b1 ], m_baseVertices[ offset1 ] ); + + m_currVertices[ i ] = deformedVertex; + } + } + + private void UpdateVerticesBone4() + { + Vector3 deformedVertex = Vector3.zero; + for ( int i = 0; i < m_vertexCount; i++ ) + { + int offset0 = i * 4; + int offset1 = offset0 + 1; + int offset2 = offset0 + 2; + int offset3 = offset0 + 3; + + int b0 = m_boneIndices[ offset0 ]; + int b1 = m_boneIndices[ offset1 ]; + int b2 = m_boneIndices[ offset2 ]; + int b3 = m_boneIndices[ offset3 ]; + + float weight1 = m_boneWeights[ offset1 ]; + float weight2 = m_boneWeights[ offset2 ]; + float weight3 = m_boneWeights[ offset3 ]; + + MulPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b0 ], m_baseVertices[ offset0 ] ); + if ( weight1 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b1 ], m_baseVertices[ offset1 ] ); + if ( weight2 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b2 ], m_baseVertices[ offset2 ] ); + if ( weight3 != 0 ) + MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b3 ], m_baseVertices[ offset3 ] ); + + m_currVertices[ i ] = deformedVertex; + } + } + + internal override void AsyncUpdate() + { + try + { + AsyncUpdateVertices( m_starting ); + } + catch ( System.Exception e ) + { + Debug.LogError( "[AmplifyMotion] Failed on SkinnedMeshRenderer data. Please contact support.\n" + e.Message ); + } + finally + { + m_asyncUpdateSignal.Set(); + } + } + +#if UNITY_4 + internal override void UpdateTransform( bool starting ) +#else + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) +#endif + { + if ( !m_initialized ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Skinned.Update" ); + + if ( !starting && m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + bool isVisible = m_renderer.isVisible; + + if ( !m_error && ( isVisible || starting ) ) + { + UpdateBones(); + + m_starting = !m_wasVisible || starting; + + if ( !m_useFallback ) + { + if ( !m_useGPU ) + { + m_asyncUpdateSignal.Reset(); + m_asyncUpdateTriggered = true; + m_owner.Instance.WorkerPool.EnqueueAsyncUpdate( this ); + } + #if !UNITY_4 + else + UpdateVerticesGPU( updateCB, m_starting ); + #endif + } + else + UpdateVerticesFallback( m_starting ); + } + + if ( !m_useFallback ) + m_currLocalToWorld = m_transform.localToWorldMatrix; + else + m_currLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one ); + + if ( starting || !m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_wasVisible = isVisible; + + Profiler.EndSample(); + } + + private void WaitForAsyncUpdate() + { + if ( m_asyncUpdateTriggered ) + { + if ( !m_asyncUpdateSignal.WaitOne( MotionState.AsyncUpdateTimeout ) ) + { + Debug.LogWarning( "[AmplifyMotion] Aborted abnormally long Async Skin deform operation. Not a critical error but might indicate a problem. Please contact support." ); + return; + } + m_asyncUpdateTriggered = false; + } + } + +#if UNITY_4 + internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Skinned.Update" ); + + if ( !m_useFallback ) + { + if ( !m_useGPU ) + WaitForAsyncUpdate(); + } + + Profiler.EndSample(); + + Profiler.BeginSample( "Skinned.Render" ); + + if ( !m_useGPU ) + { + if ( !m_useFallback ) + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + } + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + if ( m_useGPU ) + { + #if !UNITY_4 + Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight ); + + Shader.SetGlobalVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize ); + Shader.SetGlobalVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f ); + + Shader.SetGlobalTexture( "_AM_PREV_VERTEX_TEX", m_gpuPrevVertices ); + Shader.SetGlobalTexture( "_AM_CURR_VERTEX_TEX", m_gpuCurrVertices ); + #endif + } + + int hardwarePass = m_useGPU ? 4 : 0; + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + int basePass = hardwarePass + qualityPass; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = basePass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + m_owner.Instance.SkinnedVectorsMaterial.mainTexture = matDesc.material.mainTexture; + if ( matDesc.cutoff ) + m_owner.Instance.SkinnedVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + if ( m_owner.Instance.SkinnedVectorsMaterial.SetPass( pass ) ) + Graphics.DrawMeshNow( m_clonedMesh, m_currLocalToWorld, i ); + } + + Profiler.EndSample(); + } + } +#else + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_renderer.isVisible ) + { + Profiler.BeginSample( "Skinned.Update" ); + + if ( !m_useFallback ) + { + if ( !m_useGPU ) + WaitForAsyncUpdate(); + } + + Profiler.EndSample(); + + Profiler.BeginSample( "Skinned.Render" ); + if ( !m_useGPU ) + { + if ( !m_useFallback ) + m_clonedMesh.vertices = m_currVertices; + m_clonedMesh.normals = m_prevVertices; + } + + const float rcp255 = 1 / 255.0f; + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + if ( m_useGPU ) + { + #if !UNITY_4 + Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight ); + + renderCB.SetGlobalVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize ); + renderCB.SetGlobalVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f ); + + renderCB.SetGlobalTexture( "_AM_PREV_VERTEX_TEX", m_gpuPrevVertices ); + renderCB.SetGlobalTexture( "_AM_CURR_VERTEX_TEX", m_gpuCurrVertices ); + #endif + } + + int hardwarePass = m_useGPU ? 4 : 0; + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + int basePass = hardwarePass + qualityPass; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = basePass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + renderCB.DrawMesh( m_clonedMesh, m_currLocalToWorld, m_owner.Instance.SkinnedVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + + Profiler.EndSample(); + } + } +#endif + + //internal override void RenderDebugHUD() + //{ + // if ( m_useGPU && m_obj.name.Contains( "Soldier" ) ) + // { + // const int size = 180; + // int y = 180; + // + // GUI.DrawTexture( new Rect( 0, y, size, size ), m_gpuBoneIndices, ScaleMode.ScaleToFit, false ); + // GUI.DrawTexture( new Rect( size * 2, y, size, size ), m_gpuBones, ScaleMode.ScaleToFit, false ); + // y += size + 10; + // + // for ( int w = 0; w < m_weightCount; w++ ) + // GUI.DrawTexture( new Rect( w * size, y, size, size ), m_gpuBaseVertices[ w ], ScaleMode.ScaleToFit, false ); + // + // GUI.DrawTexture( new Rect( Screen.width - size * 2, y, size, size ), m_gpuPrevVertices, ScaleMode.ScaleToFit, false ); + // GUI.DrawTexture( new Rect( Screen.width - size, y, size, size ), m_gpuCurrVertices, ScaleMode.ScaleToFit, false ); + // } + //} +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta new file mode 100644 index 0000000..9638c1b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ef01d8ed1b37f1e4db5c9d687dc4b0dd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs new file mode 100644 index 0000000..87179c5 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs @@ -0,0 +1,212 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 +#define UNITY_4 +#endif +#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9 +#define UNITY_5 +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +#if !UNITY_4 +using UnityEngine.Rendering; +#endif + +namespace AmplifyMotion +{ +internal class SolidState : AmplifyMotion.MotionState +{ + public MeshRenderer m_meshRenderer; + + public Matrix4x4 m_prevLocalToWorld; + public Matrix4x4 m_currLocalToWorld; + + public Vector3 m_lastPosition; + public Quaternion m_lastRotation; + public Vector3 m_lastScale; + + private Mesh m_mesh; + + private MaterialDesc[] m_sharedMaterials; + + public bool m_moved = false; + private bool m_wasVisible; + + private static HashSet m_uniqueWarnings = new HashSet(); + + public SolidState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj ) + : base( owner, obj ) + { + m_meshRenderer = m_obj.GetComponent(); + } + + internal override void Initialize() + { + MeshFilter meshFilter = m_obj.GetComponent(); + if ( meshFilter == null || meshFilter.mesh == null ) + { + if ( !m_uniqueWarnings.Contains( m_obj ) ) + { + Debug.LogWarning( "[AmplifyMotion] Invalid MeshFilter/Mesh in object " + m_obj.name + ". Skipping." ); + m_uniqueWarnings.Add( m_obj ); + } + m_error = true; + return; + } + + base.Initialize(); + + m_mesh = meshFilter.mesh; + + m_sharedMaterials = ProcessSharedMaterials( m_meshRenderer.sharedMaterials ); + + m_wasVisible = false; + } + +#if UNITY_4 + internal override void UpdateTransform( bool starting ) +#else + internal override void UpdateTransform( CommandBuffer updateCB, bool starting ) +#endif + { + if ( !m_initialized ) + { + Initialize(); + return; + } + + Profiler.BeginSample( "Solid.Update" ); + + if ( !starting && m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_moved = true; + if ( !m_owner.Overlay ) + { + Vector3 position = m_transform.position; + Quaternion rotation = m_transform.rotation; + Vector3 scale = m_transform.lossyScale; + + m_moved = starting || + VectorChanged( position, m_lastPosition ) || + RotationChanged( rotation, m_lastRotation ) || + VectorChanged( scale, m_lastScale ); + + if ( m_moved ) + { + m_lastPosition = position; + m_lastRotation = rotation; + m_lastScale = scale; + } + } + + m_currLocalToWorld = m_transform.localToWorldMatrix; + + if ( starting || !m_wasVisible ) + m_prevLocalToWorld = m_currLocalToWorld; + + m_wasVisible = m_meshRenderer.isVisible; + + Profiler.EndSample(); + } + +#if UNITY_4 + internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_meshRenderer.isVisible ) + { + Profiler.BeginSample( "Solid.Render" ); + + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + if ( !mask || ( mask && m_moved ) ) + { + const float rcp255 = 1 / 255.0f; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + m_owner.Instance.SolidVectorsMaterial.mainTexture = matDesc.material.mainTexture; + if ( matDesc.cutoff ) + m_owner.Instance.SolidVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + if ( m_owner.Instance.SolidVectorsMaterial.SetPass( pass ) ) + Graphics.DrawMeshNow( m_mesh, m_transform.localToWorldMatrix, i ); + } + } + + Profiler.EndSample(); + } + } +#else + internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality ) + { + if ( m_initialized && !m_error && m_meshRenderer.isVisible ) + { + Profiler.BeginSample( "Solid.Render" ); + + bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0; + if ( !mask || ( mask && m_moved ) ) + { + const float rcp255 = 1 / 255.0f; + int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255; + + Matrix4x4 prevModelViewProj; + if ( m_obj.FixedStep ) + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld; + else + prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld; + + renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj ); + renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 ); + renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 ); + + // TODO: cache property blocks + + int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2; + + for ( int i = 0; i < m_sharedMaterials.Length; i++ ) + { + MaterialDesc matDesc = m_sharedMaterials[ i ]; + int pass = qualityPass + ( matDesc.coverage ? 1 : 0 ); + + if ( matDesc.coverage ) + { + Texture mainTex = matDesc.material.mainTexture; + if ( mainTex != null ) + matDesc.propertyBlock.SetTexture( "_MainTex", mainTex ); + if ( matDesc.cutoff ) + matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) ); + } + + renderCB.DrawMesh( m_mesh, m_transform.localToWorldMatrix, m_owner.Instance.SolidVectorsMaterial, i, pass, matDesc.propertyBlock ); + } + } + + Profiler.EndSample(); + } + } +#endif +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta new file mode 100644 index 0000000..dd70ecb --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/SolidState.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9d29ecb1177dbe5488d7d41e2fa8ef6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs new file mode 100644 index 0000000..7491b16 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs @@ -0,0 +1,182 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +using System; +using System.Threading; +#if NETFX_CORE +using Windows.System.Threading; +using System.Threading.Tasks; +#endif +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyMotion +{ +internal class WorkerThreadPool +{ +#if !NETFX_CORE && !UNITY_WEBGL + private const int ThreadStateQueueCapacity = 1024; + internal Queue[] m_threadStateQueues = null; + internal object[] m_threadStateQueueLocks = null; + + private int m_threadPoolSize = 0; + private ManualResetEvent m_threadPoolTerminateSignal; + private AutoResetEvent[] m_threadPoolContinueSignals; + private Thread[] m_threadPool = null; + private bool m_threadPoolFallback = false; + internal object m_threadPoolLock = null; + internal int m_threadPoolIndex = 0; +#endif + + internal void InitializeAsyncUpdateThreads( int threadCount, bool systemThreadPool ) + { + #if !NETFX_CORE && !UNITY_WEBGL + if ( systemThreadPool ) + { + m_threadPoolFallback = true; + return; + } + + try + { + m_threadPoolSize = threadCount; + m_threadStateQueues = new Queue[ m_threadPoolSize ]; + m_threadStateQueueLocks = new object[ m_threadPoolSize ]; + m_threadPool = new Thread[ m_threadPoolSize ]; + + m_threadPoolTerminateSignal = new ManualResetEvent( false ); + m_threadPoolContinueSignals = new AutoResetEvent[ m_threadPoolSize ]; + m_threadPoolLock = new object(); + m_threadPoolIndex = 0; + + for ( int id = 0; id < m_threadPoolSize; id++ ) + { + m_threadStateQueues[ id ] = new Queue( ThreadStateQueueCapacity ); + m_threadStateQueueLocks[ id ] = new object(); + + m_threadPoolContinueSignals[ id ] = new AutoResetEvent( false ); + + m_threadPool[ id ] = new Thread( new ParameterizedThreadStart( AsyncUpdateThread ) ); + m_threadPool[ id ].Start( new KeyValuePair( this, id ) ); + } + } + catch ( Exception e ) + { + // fallback to ThreadPool + Debug.LogWarning( "[AmplifyMotion] Non-critical error while initializing WorkerThreads. Falling back to using System.Threading.ThreadPool().\n" + e.Message ); + m_threadPoolFallback = true; + } + #endif + } + + internal void FinalizeAsyncUpdateThreads() + { + #if !NETFX_CORE && !UNITY_WEBGL + if ( !m_threadPoolFallback ) + { + m_threadPoolTerminateSignal.Set(); + + for ( int i = 0; i < m_threadPoolSize; i++ ) + { + if ( m_threadPool[ i ].IsAlive ) + { + m_threadPoolContinueSignals[ i ].Set(); + m_threadPool[ i ].Join(); + + // making sure these marked for disposal + m_threadPool[ i ] = null; + } + + lock ( m_threadStateQueueLocks[ i ] ) + { + while ( m_threadStateQueues[ i ].Count > 0 ) + m_threadStateQueues[ i ].Dequeue().AsyncUpdate(); + } + } + + m_threadStateQueues = null; + m_threadStateQueueLocks = null; + + m_threadPoolSize = 0; + m_threadPool = null; + m_threadPoolTerminateSignal = null; + m_threadPoolContinueSignals = null; + m_threadPoolLock = null; + m_threadPoolIndex = 0; + } + #endif + } + + internal void EnqueueAsyncUpdate( AmplifyMotion.MotionState state ) + { + #if NETFX_CORE + Task.Run( () => AsyncUpdateCallback( state ) ); + #elif UNITY_WEBGL + AsyncUpdateCallback( state ); + #else + if ( !m_threadPoolFallback ) + { + lock ( m_threadStateQueueLocks[ m_threadPoolIndex ] ) + { + m_threadStateQueues[ m_threadPoolIndex ].Enqueue( state ); + } + + m_threadPoolContinueSignals[ m_threadPoolIndex ].Set(); + + m_threadPoolIndex++; + if ( m_threadPoolIndex >= m_threadPoolSize ) + m_threadPoolIndex = 0; + } + else + ThreadPool.QueueUserWorkItem( new WaitCallback( AsyncUpdateCallback ), state ); + #endif + } + + private static void AsyncUpdateCallback( object obj ) + { + AmplifyMotion.MotionState state = ( AmplifyMotion.MotionState ) obj; + state.AsyncUpdate(); + } + + private static void AsyncUpdateThread( object obj ) + { + #if !NETFX_CORE && !UNITY_WEBGL + KeyValuePair pair = ( KeyValuePair ) obj; + WorkerThreadPool pool = ( WorkerThreadPool ) pair.Key; + int id = ( int ) pair.Value; + + while ( true ) + { + try + { + pool.m_threadPoolContinueSignals[ id ].WaitOne(); + + if ( pool.m_threadPoolTerminateSignal.WaitOne( 0 ) ) + break; + + while ( true ) + { + AmplifyMotion.MotionState state = null; + + lock ( pool.m_threadStateQueueLocks[ id ] ) + { + if ( pool.m_threadStateQueues[ id ].Count > 0 ) + state = pool.m_threadStateQueues[ id ].Dequeue(); + } + + if ( state != null ) + state.AsyncUpdate(); + else + break; + } + } + catch ( System.Exception e ) + { + if ( e.GetType() != typeof( ThreadAbortException ) ) + Debug.LogWarning( e ); + } + } + #endif + } +} +} diff --git a/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta new file mode 100644 index 0000000..5c14588 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Plugins/WorkerThreadPool.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 657ea4a21f9ed6849b837ac500e921a0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources.meta b/Assets/Cinematic Effects/MotionBlur/Resources.meta new file mode 100644 index 0000000..299f9ad --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f9e2a8bd9fe5044ac862ed1d017d8ccc +folderAsset: yes +timeCreated: 1461976949 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader new file mode 100644 index 0000000..60e3b7d --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader @@ -0,0 +1,126 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/ClothVectors" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _Cutoff ("Alpha cutoff", Range(0,1)) = 0.25 + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #include "Shared.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float3 prev_vertex : NORMAL; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float4 motion : TEXCOORD0; + float4 screen_pos : TEXCOORD1; + float2 uv : TEXCOORD2; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Cutoff; + + v2f vert_base( appdata_t v, bool mobile ) + { + v2f o; + UNITY_INITIALIZE_OUTPUT( v2f, o ); + + float4 pos = o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + float4 pos_prev = mul( _AM_MATRIX_PREV_MVP, float4( v.prev_vertex, 1 ) ); + float4 pos_curr = o.pos; + + #if UNITY_UV_STARTS_AT_TOP + pos_curr.y = -pos_curr.y; + pos_prev.y = -pos_prev.y; + if ( _ProjectionParams.x > 0 ) + pos.y = -pos.y; + #endif + + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + + if ( mobile ) + o.motion = DeformableMotionVector( ( pos_curr.xyz - pos_prev.xyz ) * _AM_MOTION_SCALE, _AM_OBJECT_ID ); + else + o.motion.xyz = ( pos_curr.xyz - pos_prev.xyz ) * _AM_MOTION_SCALE; + + o.screen_pos = ComputeScreenPos( pos ); + o.uv = TRANSFORM_TEX( v.texcoord, _MainTex ); + return o; + } + + inline half4 frag_opaque( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + + inline half4 frag_cutout( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) || tex2D( _MainTex, i.uv ).a < _Cutoff ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + ENDCG + SubShader { + Tags { "RenderType"="Opaque" } + Blend Off Cull Off Fog { Mode off } + ZTest LEqual ZWrite On + Offset -1, -1 + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + } + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta new file mode 100644 index 0000000..9414595 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ClothVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1768f062f9aaadc49b754774fc1c5c47 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader new file mode 100644 index 0000000..8fac628 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader @@ -0,0 +1,75 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Combine" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + _CameraMotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #include "UnityCG.cginc" + + sampler2D _MainTex; + sampler2D _MotionTex; + sampler2D _BlurredTex; + float4 _MainTex_TexelSize; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; + #if defined( UNITY_UV_STARTS_AT_TOP ) + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; + #endif + return o; + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // Combine source RGB and motion object ID + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + half4 frag( v2f i ) : SV_Target + { + return half4( tex2D( _MainTex, i.uv.xy ).xyz, tex2D( _MotionTex, i.uv.zw ).a + 0.0000001f ); // hack to trick Unity into behaving + } + ENDCG + } + + // Combine motion blurred lowres and non-blurred full res (mobile mode) + Pass { + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + half4 frag( v2f i ) : SV_Target + { + half4 source = tex2D( _MainTex, i.uv.xy ); + half mag = 2 * tex2D( _MotionTex, i.uv.zw ).z; + return half4( source.rgb, 1 - saturate( mag * 1.5 ) ); + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta new file mode 100644 index 0000000..41d8eb6 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Combine.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 930d72fd71d3a464b9ac2e51161a269e +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader new file mode 100644 index 0000000..16f8a44 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader @@ -0,0 +1,56 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Debug" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + SubShader { + Pass { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #include "UnityCG.cginc" + + sampler2D _MainTex; + sampler2D _MotionTex; + sampler2D _CameraDepthTexture; + float4 _MainTex_TexelSize; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; + #endif + return o; + } + + half4 frag( v2f i ) : SV_Target + { + half4 motion = tex2D( _MotionTex, i.uv.zw ); + half2 vec = ( motion.xy * 2 - 1 ) * motion.z; + half id = motion.w; + return half4( vec, id * 10, 1 ); + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta new file mode 100644 index 0000000..ba1d73b --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Debug.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e352ad1d36bf8904c927cfbcecf998d1 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader new file mode 100644 index 0000000..8c51fa6 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader @@ -0,0 +1,139 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Depth" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #include "UnityCG.cginc" + + sampler2D _CameraDepthTexture; + float4 _CameraDepthTexture_TexelSize; + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + sampler2D _MotionTex; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + float4 uv0 : TEXCOORD1; + float4 uv1 : TEXCOORD2; + float4 uv2 : TEXCOORD3; + float4 uv3 : TEXCOORD4; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + + const float4 texels = float4( _MainTex_TexelSize.xy, _CameraDepthTexture_TexelSize.xy ); + const float4 offsets[ 4 ] = { + float4( 0.5, 0.5, 0.5, 0.5 ), + float4( 1.5, 0.5, 1.5, 0.5 ), + float4( 1.5, 1.5, 1.5, 1.5 ), + float4( 0.5, 1.5, 0.5, 1.5 ) + }; + + o.uv = v.texcoord.xyxy; + o.uv0 = v.texcoord.xyxy + texels * offsets[ 0 ]; + o.uv1 = v.texcoord.xyxy + texels * offsets[ 1 ]; + o.uv2 = v.texcoord.xyxy + texels * offsets[ 2 ]; + o.uv3 = v.texcoord.xyxy + texels * offsets[ 3 ]; + + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + { + o.uv.w = 1 - o.uv.w; + o.uv0.w = 1 - o.uv0.w; + o.uv1.w = 1 - o.uv1.w; + o.uv2.w = 1 - o.uv2.w; + o.uv3.w = 1 - o.uv3.w; + } + #endif + return o; + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // Straight Copy + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + fixed4 frag( v2f i ) : SV_Target + { + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + return ( depth == 1.0 ) ? ( 1.0 ).xxxx : EncodeFloatRGBA( depth ); + } + ENDCG + } + + // 4-Tap MinZ Depth Downsampling + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + half4 frag( v2f i ) : SV_Target + { + float depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv0.zw ); + float depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv1.zw ); + float depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv2.zw ); + float depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv3.zw ); + + float depth = depth0; + depth = ( depth1 < depth ) ? depth1 : depth; + depth = ( depth2 < depth ) ? depth2 : depth; + depth = ( depth3 < depth ) ? depth3 : depth; + + return depth.xxxx; + } + ENDCG + } + + // 4-Tap Depth-Aware (MinZ) Combined Downsampling + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + half4 frag( v2f i ) : SV_Target + { + float depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv0.zw ); + float depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv1.zw ); + float depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv2.zw ); + float depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv3.zw ); + + half4 combo0 = half4( tex2D( _MainTex, i.uv0.xy ).xyz, tex2D( _MotionTex, i.uv0.zw ).a + 0.0000001 ); + half4 combo1 = half4( tex2D( _MainTex, i.uv1.xy ).xyz, tex2D( _MotionTex, i.uv1.zw ).a + 0.0000001 ); + half4 combo2 = half4( tex2D( _MainTex, i.uv2.xy ).xyz, tex2D( _MotionTex, i.uv2.zw ).a + 0.0000001 ); + half4 combo3 = half4( tex2D( _MainTex, i.uv3.xy ).xyz, tex2D( _MotionTex, i.uv3.zw ).a + 0.0000001 ); + + half4 combo = combo0; + float depth = depth0; + + combo = ( depth1 < depth ) ? combo1 : combo; + depth = ( depth1 < depth ) ? depth1 : depth; + combo = ( depth2 < depth ) ? combo2 : combo; + depth = ( depth2 < depth ) ? depth2 : depth; + combo = ( depth3 < depth ) ? combo3 : combo; + depth = ( depth3 < depth ) ? depth3 : depth; + + return combo; + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta new file mode 100644 index 0000000..f1d5439 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Depth.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6e53249b629741a4eb9dc58c3f2b617d +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader new file mode 100644 index 0000000..447f9ee --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader @@ -0,0 +1,160 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/Dilation" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + #include "UnityCG.cginc" + + sampler2D _CameraDepthTexture; + sampler2D _MotionTex; + float4 _MainTex_TexelSize; + + struct v2f + { + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; + #endif + return o; + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // Separable Dilation - 3-Tap Horizontal + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_horizontal + + half4 frag_horizontal( v2f i ) : SV_Target + { + float tx = _MainTex_TexelSize.x; + float2 offsets[ 3 ] = { float2( -tx, 0 ), float2( 0, 0 ), float2( tx, 0 ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 3; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + + // Separable Dilation - 3-Tap Vertical + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_vertical + + half4 frag_vertical( v2f i ) : SV_Target + { + float ty = _MainTex_TexelSize.y; + float2 offsets[ 3 ] = { float2( 0, -ty ), float2( 0, 0 ), float2( 0, ty ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 3; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + + // Separable Dilation - 5-Tap Horizontal + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_horizontal + + half4 frag_horizontal( v2f i ) : SV_Target + { + float tx1 = _MainTex_TexelSize.x; + float tx2 = tx1 + tx1; + float2 offsets[ 5 ] = { float2( -tx2, 0 ), float2( -tx1, 0 ), float2( 0, 0 ), float2( tx1, 0 ), float2( tx2, 0 ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 5; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + + // Separable Dilation - 5-Tap Vertical + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_vertical + + half4 frag_vertical( v2f i ) : SV_Target + { + float ty1 = _MainTex_TexelSize.y; + float ty2 = ty1 + ty1; + float2 offsets[ 5 ] = { float2( 0, -ty2 ), float2( 0, -ty1 ), float2( 0, 0 ), float2( 0, ty1 ), float2( 0, ty2 ) }; + + half4 motion_ref = tex2D( _MotionTex, i.uv.zw ); + float depth_ref = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.zw ); + half4 result = motion_ref; + + for ( int tap = 0; tap < 5; tap++ ) + { + float2 tap_uv = i.uv.zw + offsets[ tap ]; + + half4 motion = tex2D( _MotionTex, tap_uv ); + float depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, tap_uv ); + result = ( depth < depth_ref ) ? motion : result; + } + + return result; + } + ENDCG + } + } + + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta new file mode 100644 index 0000000..dadf1af --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Dilation.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 83053a1495b64ea47942703db953dfb1 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader new file mode 100644 index 0000000..654fec2 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader @@ -0,0 +1,113 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/GPUSkinDeform" { + Properties { } + CGINCLUDE + #pragma target 3.0 + #pragma glsl + #include "UnityCG.cginc" + + sampler2D _AM_BONE_TEX; + sampler2D _AM_BONE_INDEX_TEX; + sampler2D _AM_BASE_VERTEX0_TEX; + sampler2D _AM_BASE_VERTEX1_TEX; + sampler2D _AM_BASE_VERTEX2_TEX; + sampler2D _AM_BASE_VERTEX3_TEX; + + float4 _AM_BONE_TEXEL_SIZE; + float4 _AM_BONE_TEXEL_HALFSIZE; + + float4x4 _AM_WORLD_TO_LOCAL_MATRIX; + + inline float4x4 fetch_bone( float index ) + { + float4 row0 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 0 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + float4 row1 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 1 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + float4 row2 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 2 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + float4 row3 = tex2Dlod( _AM_BONE_TEX, float4( float2( index, 3 ) * _AM_BONE_TEXEL_SIZE.xy + _AM_BONE_TEXEL_HALFSIZE.xy, 0, 0 ) ); + return float4x4( row0, row1, row2, row3 ); + } + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + + // 1 weight per-vertex + Pass { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + float4 frag( v2f_img i ) : SV_Target + { + float4 boneIndices = tex2Dlod( _AM_BONE_INDEX_TEX, float4( i.uv, 0, 0 ) ); + + float4 baseVertex0 = tex2Dlod( _AM_BASE_VERTEX0_TEX, float4( i.uv, 0, 0 ) ); + + float4x4 bone0 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.x ) ); + + float4 deformedVertex; + deformedVertex = mul( bone0, baseVertex0 ); + + return float4( deformedVertex.xyz, 1 ); + } + ENDCG + } + + // 2 weights per-vertex + Pass { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + float4 frag( v2f_img i ) : SV_Target + { + float4 boneIndices = tex2Dlod( _AM_BONE_INDEX_TEX, float4( i.uv, 0, 0 ) ); + + float4 baseVertex0 = tex2Dlod( _AM_BASE_VERTEX0_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex1 = tex2Dlod( _AM_BASE_VERTEX1_TEX, float4( i.uv, 0, 0 ) ); + + float4x4 bone0 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.x ) ); + float4x4 bone1 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.y ) ); + + float4 deformedVertex; + deformedVertex = mul( bone0, baseVertex0 ); + deformedVertex += mul( bone1, baseVertex1 ); + + return float4( deformedVertex.xyz, 1 ); + } + ENDCG + } + + // 4 weights per-vertex + Pass { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + float4 frag( v2f_img i ) : SV_Target + { + float4 boneIndices = tex2Dlod( _AM_BONE_INDEX_TEX, float4( i.uv, 0, 0 ) ); + + float4 baseVertex0 = tex2Dlod( _AM_BASE_VERTEX0_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex1 = tex2Dlod( _AM_BASE_VERTEX1_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex2 = tex2Dlod( _AM_BASE_VERTEX2_TEX, float4( i.uv, 0, 0 ) ); + float4 baseVertex3 = tex2Dlod( _AM_BASE_VERTEX3_TEX, float4( i.uv, 0, 0 ) ); + + float4x4 bone0 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.x ) ); + float4x4 bone1 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.y ) ); + float4x4 bone2 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.z ) ); + float4x4 bone3 = mul( _AM_WORLD_TO_LOCAL_MATRIX, fetch_bone( boneIndices.w ) ); + + float4 deformedVertex; + deformedVertex = mul( bone0, baseVertex0 ); + deformedVertex += mul( bone1, baseVertex1 ); + deformedVertex += mul( bone2, baseVertex2 ); + deformedVertex += mul( bone3, baseVertex3 ); + + return float4( deformedVertex.xyz, 1 ); + } + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta new file mode 100644 index 0000000..5174a7e --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/GPUSkinDeform.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f9650ce6454d854dad8d0372917779e +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader new file mode 100644 index 0000000..ee10188 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader @@ -0,0 +1,35 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/MotionBlurSM2" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + #include "MotionBlurShared.cginc" + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + Pass { + Name "MOB" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_mobile + #pragma target 2.0 + ENDCG + } + Pass { + Name "STD" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_sm2 + #pragma target 2.0 + ENDCG + } + } + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta new file mode 100644 index 0000000..2909ca7 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM2.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ebf06ea1548615049bfb691bcb60d35b +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader new file mode 100644 index 0000000..cf81ccd --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader @@ -0,0 +1,53 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/MotionBlurSM3" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _MotionTex ("Motion (RGB)", 2D) = "white" {} + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #pragma exclude_renderers flash + + #include "MotionBlurShared.cginc" + ENDCG + SubShader { + ZTest Always Cull Off ZWrite Off Fog { Mode off } + Pass { + Name "MOB" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_mobile + #pragma target 2.0 + ENDCG + } + Pass { + Name "STD" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_sm2 + #pragma target 2.0 + ENDCG + } + Pass { + Name "STD_SM3" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_sm3 + #pragma target 3.0 + #pragma exclude_renderers d3d11_9x + ENDCG + } + Pass { + Name "SOFT_SM3" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_soft_sm3 + #pragma target 3.0 + #pragma exclude_renderers d3d11_9x + ENDCG + } + } + Fallback Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta new file mode 100644 index 0000000..cb68c00 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurSM3.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b9e697d6188428a43830f6aad3d2c114 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc new file mode 100644 index 0000000..8c2eaf3 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc @@ -0,0 +1,236 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#ifndef AMPLIFY_MOTION_BLUR_SHARED_INCLUDED +#define AMPLIFY_MOTION_BLUR_SHARED_INCLUDED + +#include "UnityCG.cginc" + +sampler2D _MainTex; +float4 _MainTex_TexelSize; + +sampler2D _CameraDepthTexture; +float4 _CameraDepthTexture_TexelSize; + +sampler2D _DepthTex; +float4 _DepthTex_TexelSize; +sampler2D _MotionTex; + +half4 _AM_BLUR_STEP; +half2 _AM_DEPTH_THRESHOLD; + +struct v2f +{ + float4 pos : SV_POSITION; + float4 uv : TEXCOORD0; +}; + +v2f vert( appdata_img v ) +{ + v2f o = ( v2f ) 0; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv.xy = v.texcoord.xy; + o.uv.zw = v.texcoord.xy; +#if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv.w = 1 - o.uv.w; +#endif + return o; +} + +half4 frag_mobile( v2f i ) : SV_Target +{ + // 3-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = saturate( DecodeFloatRGBA( tex2D( _DepthTex, i.uv.xy ) ) ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + + half sample_depth0 = saturate( DecodeFloatRGBA( tex2D( _DepthTex, i.uv.xy - dir_step ) ) ); + half sample_depth1 = saturate( DecodeFloatRGBA( tex2D( _DepthTex, i.uv.xy + dir_step ) ) ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy + dir_step ); + + half2 sample_depth = half2( sample_depth0, sample_depth1 ); + half2 sample_id = half2( sample_color0.a, sample_color1.a ); + + half2 depth_test = sample_depth > ( ref_depth.xx - _AM_DEPTH_THRESHOLD.xx ); + half2 obj_test = ref_isobj.xx * ( sample_id == ref_id.xx ); + + half2 sample_test = saturate( depth_test + obj_test ); + + accum += sample_test.x * half4( sample_color0.xyz, 1 ); + accum += sample_test.y * half4( sample_color1.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +half4 frag_sm2( v2f i ) : SV_Target +{ + // 5-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + half2 dir_step1 = dir_step * 0.5; + + half sample_depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step ); + half sample_depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step1 ); + half sample_depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step1 ); + half sample_depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy - dir_step1 ); + half4 sample_color2 = tex2D( _MainTex, i.uv.xy + dir_step1 ); + half4 sample_color3 = tex2D( _MainTex, i.uv.xy + dir_step ); + + half4 sample_depth = half4( sample_depth0, sample_depth1, sample_depth2, sample_depth3 ); + half4 sample_id = half4( sample_color0.a, sample_color1.a, sample_color2.a, sample_color3.a ); + + half4 depth_test = sample_depth > ( ref_depth.xxxx - _AM_DEPTH_THRESHOLD.xxxx ); + half4 obj_test = ref_isobj.xxxx * ( sample_id == ref_id.xxxx ); + + half4 sample_test = saturate( depth_test + obj_test ); + + accum += sample_test.x * half4( sample_color0.xyz, 1 ); + accum += sample_test.y * half4( sample_color1.xyz, 1 ); + accum += sample_test.z * half4( sample_color2.xyz, 1 ); + accum += sample_test.w * half4( sample_color3.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +half4 frag_sm3( v2f i ) : SV_Target +{ + // 9-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + half2 dir_step1 = dir_step * 0.75; + half2 dir_step2 = dir_step * 0.50; + half2 dir_step3 = dir_step * 0.25; + + half sample_depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step ); + half sample_depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step1 ); + half sample_depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step2 ); + half sample_depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step3 ); + half sample_depth4 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step3 ); + half sample_depth5 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step2 ); + half sample_depth6 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step1 ); + half sample_depth7 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step ); + + half4 sample_depthA = half4( sample_depth0, sample_depth1, sample_depth2, sample_depth3 ); + half4 sample_depthB = half4( sample_depth4, sample_depth5, sample_depth6, sample_depth7 ); + + half4 diffA = ref_depth.xxxx - sample_depthA; + half4 diffB = ref_depth.xxxx - sample_depthB; + half4 diff_testA = diffA < _AM_DEPTH_THRESHOLD.xxxx; + half4 diff_testB = diffB < _AM_DEPTH_THRESHOLD.xxxx; + half4 sample_testA = diff_testA - diff_testA * saturate( diffA * _AM_DEPTH_THRESHOLD.yyyy ); + half4 sample_testB = diff_testB - diff_testB * saturate( diffB * _AM_DEPTH_THRESHOLD.yyyy ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step * sample_testA.x ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy - dir_step1 * sample_testA.y ); + half4 sample_color2 = tex2D( _MainTex, i.uv.xy - dir_step2 * sample_testA.z ); + half4 sample_color3 = tex2D( _MainTex, i.uv.xy - dir_step3 * sample_testA.w ); + half4 sample_color4 = tex2D( _MainTex, i.uv.xy + dir_step3 * sample_testB.x ); + half4 sample_color5 = tex2D( _MainTex, i.uv.xy + dir_step2 * sample_testB.y ); + half4 sample_color6 = tex2D( _MainTex, i.uv.xy + dir_step1 * sample_testB.z ); + half4 sample_color7 = tex2D( _MainTex, i.uv.xy + dir_step * sample_testB.w ); + + half4 sample_idA = half4( sample_color0.a, sample_color1.a, sample_color2.a, sample_color3.a ); + half4 sample_idB = half4( sample_color4.a, sample_color5.a, sample_color6.a, sample_color7.a ); + + half4 obj_testA = ref_isobj.xxxx * ( sample_idA == ref_id.xxxx ); + half4 obj_testB = ref_isobj.xxxx * ( sample_idB == ref_id.xxxx ); + + sample_testA = saturate( sample_testA + obj_testA ); + sample_testB = saturate( sample_testB + obj_testB ); + + accum += sample_testA.x * half4( sample_color0.xyz, 1 ); + accum += sample_testA.y * half4( sample_color1.xyz, 1 ); + accum += sample_testA.z * half4( sample_color2.xyz, 1 ); + accum += sample_testA.w * half4( sample_color3.xyz, 1 ); + accum += sample_testB.x * half4( sample_color4.xyz, 1 ); + accum += sample_testB.y * half4( sample_color5.xyz, 1 ); + accum += sample_testB.z * half4( sample_color6.xyz, 1 ); + accum += sample_testB.w * half4( sample_color7.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +half4 frag_soft_sm3( v2f i ) : SV_Target +{ + // 5-TAP + half3 motion = tex2D( _MotionTex, i.uv.zw ).xyz; + half4 color = tex2D( _MainTex, i.uv.xy ); + half4 accum = half4( color.xyz, 1 ); + + half ref_depth = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy ); + half ref_id = color.a; + + half id = floor( color.a * 255 + 0.5 ); + half ref_isobj = ( id > 1 ) * ( id < 254 ); + + half2 dir_step = _AM_BLUR_STEP.xy * ( motion.xy * 2.0 - 1.0 ) * motion.z; + half2 dir_step1 = dir_step * 0.5; + + half sample_depth0 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step ); + half sample_depth1 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy - dir_step1 ); + half sample_depth2 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step1 ); + half sample_depth3 = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv.xy + dir_step ); + + half4 sample_color0 = tex2D( _MainTex, i.uv.xy - dir_step ); + half4 sample_color1 = tex2D( _MainTex, i.uv.xy - dir_step1 ); + half4 sample_color2 = tex2D( _MainTex, i.uv.xy + dir_step1 ); + half4 sample_color3 = tex2D( _MainTex, i.uv.xy + dir_step ); + + half sample_mag0 = tex2D( _MotionTex, i.uv.xy - dir_step ).z; + half sample_mag1 = tex2D( _MotionTex, i.uv.xy - dir_step1 ).z; + half sample_mag2 = tex2D( _MotionTex, i.uv.xy + dir_step1 ).z; + half sample_mag3 = tex2D( _MotionTex, i.uv.xy + dir_step ).z; + + half4 sample_depth = half4( sample_depth0, sample_depth1, sample_depth2, sample_depth3 ); + half4 sample_id = half4( sample_color0.a, sample_color1.a, sample_color2.a, sample_color3.a ); + half4 sample_mag = half4( sample_mag0, sample_mag1, sample_mag2, sample_mag3 ); + + half4 thres_mag = ( 0.5 ).xxxx; + + half4 depth_test = sample_depth > ( ref_depth.xxxx - _AM_DEPTH_THRESHOLD.xxxx ); + half4 obj_test = ref_isobj.xxxx * ( sample_id == ref_id.xxxx ); + half4 mag_test = sample_mag > thres_mag; + + half4 sample_test = saturate( depth_test + obj_test + mag_test ); + + accum += sample_test.x * half4( sample_color0.xyz, 1 ); + accum += sample_test.y * half4( sample_color1.xyz, 1 ); + accum += sample_test.z * half4( sample_color2.xyz, 1 ); + accum += sample_test.w * half4( sample_color3.xyz, 1 ); + + return half4( accum.xyz / accum.w, ref_id ); +} + +#endif diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta new file mode 100644 index 0000000..a75cc0f --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/MotionBlurShared.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6df9775b9d7b1b14b818b28c92892dae +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader new file mode 100644 index 0000000..16e36f8 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader @@ -0,0 +1,73 @@ + +Shader "Hidden/Amplify Motion/ReprojectionVectors" { + Properties { + _MainTex ("-", 2D) = "" {} + } + SubShader { + Cull Off ZTest Always ZWrite Off Blend Off Fog { Mode Off } + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv_rt : TEXCOORD1; + }; + + sampler2D _CameraDepthTexture; + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + float4x4 _AM_MATRIX_CURR_REPROJ; + float _AM_MOTION_SCALE; + float _AM_MIN_VELOCITY; + float _AM_MAX_VELOCITY; + float _AM_RCP_TOTAL_VELOCITY; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + o.uv = v.texcoord.xy; + o.uv_rt = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if ( _MainTex_TexelSize.y < 0 ) + o.uv_rt.y = 1 - o.uv_rt.y; + #endif + return o; + } + + half4 frag( v2f i ) : SV_Target + { + float d = SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, i.uv_rt ); + #if defined( SHADER_API_OPENGL ) || defined( SHADER_API_GLES ) || defined( SHADER_API_GLES3 ) + float4 pos_curr = float4( float3( i.uv.xy, d ) * 2 - 1, 1 ); + #else + float4 pos_curr = float4( i.uv.xy * 2 - 1, d, 1 ); + #endif + + // 1) unproject to world; 2) reproject into previous ViewProj + float4 pos_prev = mul( _AM_MATRIX_CURR_REPROJ, pos_curr ); + + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + + half4 motion = ( pos_curr - pos_prev ) * _AM_MOTION_SCALE; + + motion.z = length( motion.xy ); + motion.xy = ( motion.xy / motion.z ) * 0.5f + 0.5f; + motion.z = ( motion.z < _AM_MIN_VELOCITY ) ? 0 : motion.z; + motion.z = max( min( motion.z, _AM_MAX_VELOCITY ) - _AM_MIN_VELOCITY, 0 ) * _AM_RCP_TOTAL_VELOCITY; + + return half4( motion.xyz, 0 ); + } + ENDCG + } + } + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta new file mode 100644 index 0000000..cd27c34 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/ReprojectionVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7d54d4ac3d05c2246aebc73a9b2dbf66 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc new file mode 100644 index 0000000..763db79 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc @@ -0,0 +1,59 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +#ifndef AMPLIFY_MOTION_SHARED_INCLUDED +#define AMPLIFY_MOTION_SHARED_INCLUDED + +#include "UnityCG.cginc" + +sampler2D _CameraDepthTexture; +float4x4 _AM_MATRIX_PREV_MVP; +float4 _AM_ZBUFFER_PARAMS; +float _AM_OBJECT_ID; +float _AM_MOTION_SCALE; +float _AM_MIN_VELOCITY; +float _AM_MAX_VELOCITY; +float _AM_RCP_TOTAL_VELOCITY; + +sampler2D _AM_PREV_VERTEX_TEX; +sampler2D _AM_CURR_VERTEX_TEX; + +float4 _AM_VERTEX_TEXEL_SIZE; +float4 _AM_VERTEX_TEXEL_HALFSIZE; + +inline bool DepthTest( float4 screen_pos ) +{ + const float epsilon = 0.001f; + float3 uv = screen_pos.xyz / screen_pos.w; + float behind = SAMPLE_DEPTH_TEXTURE_PROJ( _CameraDepthTexture, screen_pos ); +#if defined( SHADER_API_OPENGL ) || defined( SHADER_API_GLES ) || defined( SHADER_API_GLES3 ) + float front = uv.z * 0.5 + 0.5; +#else + float front = uv.z; +#endif + return ( behind >= front - epsilon ); +} + +inline half4 SolidMotionVector( half4 pos_prev, half4 pos_curr, half obj_id ) +{ + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + half4 motion = ( pos_curr - pos_prev ) * _AM_MOTION_SCALE; + + motion.z = length( motion.xy ); + motion.xy = ( motion.xy / motion.z ) * 0.5f + 0.5f; + motion.z = ( motion.z < _AM_MIN_VELOCITY ) ? 0 : motion.z; + motion.z = max( min( motion.z, _AM_MAX_VELOCITY ) - _AM_MIN_VELOCITY, 0 ) * _AM_RCP_TOTAL_VELOCITY; + return half4( motion.xyz, obj_id ); +} + +inline half4 DeformableMotionVector( half3 motion, half obj_id ) +{ + motion.z = length( motion.xy ); + motion.xy = ( motion.xy / motion.z ) * 0.5f + 0.5f; + motion.z = ( motion.z < _AM_MIN_VELOCITY ) ? 0 : motion.z; + motion.z = max( min( motion.z, _AM_MAX_VELOCITY ) - _AM_MIN_VELOCITY, 0 ) * _AM_RCP_TOTAL_VELOCITY; + return half4( motion.xyz, obj_id ); +} + +#endif diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta new file mode 100644 index 0000000..71cac07 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/Shared.cginc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f73e8f36393c28544851bd0262522296 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader new file mode 100644 index 0000000..aee4a7a --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader @@ -0,0 +1,189 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/SkinnedVectors" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _Cutoff ("Alpha cutoff", Range(0,1)) = 0.25 + } + CGINCLUDE + #include "Shared.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float3 prev_vertex : NORMAL; + float2 texcoord : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float4 motion : TEXCOORD0; + float4 screen_pos : TEXCOORD1; + float2 uv : TEXCOORD2; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Cutoff; + + inline v2f vert_base( appdata_t v, const bool mobile, const bool gpu ) + { + v2f o; + UNITY_INITIALIZE_OUTPUT( v2f, o ); + + float4 prev_vertex = float4( v.prev_vertex.xyz, 1 ); + float4 curr_vertex = float4( v.vertex.xyz, 1 ); + + #if UNITY_VERSION >= 500 + if ( gpu ) + { + prev_vertex = 0; + curr_vertex *= 0.00000001; // trick compiler into behaving + + float2 indexCoords = v.texcoord1; + prev_vertex += tex2Dlod( _AM_PREV_VERTEX_TEX, float4( indexCoords, 0, 0 ) ); + curr_vertex += tex2Dlod( _AM_CURR_VERTEX_TEX, float4( indexCoords, 0, 0 ) ); + } + #endif + + float4 pos = o.pos = mul( UNITY_MATRIX_MVP, curr_vertex ); + float4 pos_prev = mul( _AM_MATRIX_PREV_MVP, prev_vertex ); + float4 pos_curr = o.pos; + + #if UNITY_UV_STARTS_AT_TOP + pos_curr.y = -pos_curr.y; + pos_prev.y = -pos_prev.y; + if ( _ProjectionParams.x > 0 ) + pos.y = -pos.y; + #endif + + pos_prev = pos_prev / pos_prev.w; + pos_curr = pos_curr / pos_curr.w; + + if ( mobile ) + o.motion = DeformableMotionVector( ( pos_curr.xyz - pos_prev.xyz ) * _AM_MOTION_SCALE, _AM_OBJECT_ID ); + else + o.motion.xyz = ( pos_curr - pos_prev ) * _AM_MOTION_SCALE; + + o.screen_pos = ComputeScreenPos( pos ); + o.uv = TRANSFORM_TEX( v.texcoord, _MainTex ); + return o; + } + + inline half4 frag_opaque( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + + inline half4 frag_cutout( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) || tex2D( _MainTex, i.uv ).a < _Cutoff ) + discard; + + if ( mobile ) + return i.motion; + else + return DeformableMotionVector( i.motion, _AM_OBJECT_ID ); + } + ENDCG + SubShader { + Tags { "RenderType"="Opaque" } + Blend Off Cull Off Fog { Mode off } + ZTest LEqual ZWrite On + Offset -1, -1 + + // CPU path + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, true, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, true, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, false, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + v2f vert( appdata_t v ) { return vert_base( v, false, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + + // GPU path + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, true, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, true, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, false, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 3.0 + v2f vert( appdata_t v ) { return vert_base( v, false, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + } + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta new file mode 100644 index 0000000..e786a23 --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SkinnedVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ed3e87d88a83040418d4b34782b7b422 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader new file mode 100644 index 0000000..3c3177d --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader @@ -0,0 +1,127 @@ +// Amplify Motion - Full-scene Motion Blur for Unity Pro +// Copyright (c) Amplify Creations, Lda + +Shader "Hidden/Amplify Motion/SolidVectors" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + _Cutoff ("Alpha cutoff", Range(0,1)) = 0.25 + } + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + #include "Shared.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float4 pos_prev : TEXCOORD0; + float4 pos_curr : TEXCOORD1; + float4 motion : TEXCOORD2; + float4 screen_pos : TEXCOORD3; + float2 uv : TEXCOORD4; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Cutoff; + + v2f vert_base( appdata_t v, bool mobile ) + { + v2f o; + UNITY_INITIALIZE_OUTPUT( v2f, o ); + + float4 pos = o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); + float4 pos_prev = mul( _AM_MATRIX_PREV_MVP, v.vertex ); + float4 pos_curr = o.pos; + + #if UNITY_UV_STARTS_AT_TOP + pos_curr.y = -pos_curr.y; + pos_prev.y = -pos_prev.y; + if ( _ProjectionParams.x > 0 ) + pos.y = -pos.y; + #endif + + if ( mobile ) + o.motion = SolidMotionVector( pos_prev, pos_curr, _AM_OBJECT_ID ); + else + { + o.pos_prev = pos_prev; + o.pos_curr = pos_curr; + } + + o.screen_pos = ComputeScreenPos( pos ); + o.uv = TRANSFORM_TEX( v.texcoord, _MainTex ); + return o; + } + + inline half4 frag_opaque( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) ) + discard; + + if ( mobile ) + return i.motion; + else + return SolidMotionVector( i.pos_prev, i.pos_curr, _AM_OBJECT_ID ); + } + + inline half4 frag_cutout( v2f i, const bool mobile ) + { + if ( !DepthTest( i.screen_pos ) || tex2D( _MainTex, i.uv ).a < _Cutoff ) + discard; + + if ( mobile ) + return i.motion; + else + return SolidMotionVector( i.pos_prev, i.pos_curr, _AM_OBJECT_ID ); + } + ENDCG + SubShader { + Tags { "RenderType"="Opaque" } + Blend Off Cull Off Fog { Mode off } + ZTest LEqual ZWrite On + Pass { + Name "MOB_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, true ); } + ENDCG + } + Pass { + Name "MOB_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, true ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, true ); } + ENDCG + } + Pass { + Name "STD_OPAQUE" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_opaque( v, false ); } + ENDCG + } + Pass { + Name "STD_CUTOUT" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + v2f vert( appdata_t v ) { return vert_base( v, false ); } + half4 frag( v2f v ) : SV_Target { return frag_cutout( v, false ); } + ENDCG + } + } + + FallBack Off +} diff --git a/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta new file mode 100644 index 0000000..63712bf --- /dev/null +++ b/Assets/Cinematic Effects/MotionBlur/Resources/SolidVectors.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a9c02c5d9708d884c87086d5f4f8765a +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection.meta b/Assets/Cinematic Effects/ScreenSpaceReflection.meta new file mode 100644 index 0000000..914d7cb --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0190f05cacbdca84c932a2f2e0035c51 +folderAsset: yes +timeCreated: 1448358989 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta new file mode 100644 index 0000000..6368712 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4834a3e1213004b48b14703e6723c17c +folderAsset: yes +timeCreated: 1448359076 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs new file mode 100644 index 0000000..ccab011 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomPropertyDrawer(typeof(ScreenSpaceReflection.SSRSettings.LayoutAttribute))] + public class LayoutDrawer : PropertyDrawer + { + private const float kHeadingSpace = 22.0f; + + static Styles m_Styles; + + private class Styles + { + public readonly GUIStyle header = "ShurikenModuleTitle"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + header.border = new RectOffset(15, 7, 4, 4); + header.fixedHeight = kHeadingSpace; + header.contentOffset = new Vector2(20f, -2f); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + if (!property.isExpanded) + return kHeadingSpace; + + var count = property.CountInProperty(); + return EditorGUIUtility.singleLineHeight * count + 15; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (m_Styles == null) + m_Styles = new Styles(); + + position.height = EditorGUIUtility.singleLineHeight; + property.isExpanded = Header(position, property.displayName, property.isExpanded); + position.y += kHeadingSpace; + + if (!property.isExpanded) + return; + + foreach (SerializedProperty child in property) + { + EditorGUI.PropertyField(position, child); + position.y += EditorGUIUtility.singleLineHeight; + } + } + + private bool Header(Rect position, String title, bool display) + { + Rect rect = position; + position.height = EditorGUIUtility.singleLineHeight; + GUI.Box(rect, title, m_Styles.header); + + Rect toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f); + if (Event.current.type == EventType.Repaint) + EditorStyles.foldout.Draw(toggleRect, false, false, display, false); + + Event e = Event.current; + if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) + { + display = !display; + e.Use(); + } + return display; + } + } + + [CustomEditor(typeof(ScreenSpaceReflection))] + internal class ScreenSpaceReflectionEditor : Editor + { + private enum SettingsMode + { + HighQuality, + Default, + Performance, + Custom, + } + + [NonSerialized] + private List m_Properties = new List(); + + void OnEnable() + { + var settings = FieldFinder.GetField(x => x.settings); + foreach (var setting in settings.FieldType.GetFields()) + { + var prop = settings.Name + "." + setting.Name; + m_Properties.Add(serializedObject.FindProperty(prop)); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.Space(); + + var currentState = ((ScreenSpaceReflection)target).settings; + + var settingsMode = SettingsMode.Custom; + if (currentState.Equals(ScreenSpaceReflection.SSRSettings.performanceSettings)) + settingsMode = SettingsMode.Performance; + else if (currentState.Equals(ScreenSpaceReflection.SSRSettings.defaultSettings)) + settingsMode = SettingsMode.Default; + else if (currentState.Equals(ScreenSpaceReflection.SSRSettings.highQualitySettings)) + settingsMode = SettingsMode.HighQuality; + + EditorGUI.BeginChangeCheck(); + settingsMode = (SettingsMode)EditorGUILayout.EnumPopup("Preset", settingsMode); + if (EditorGUI.EndChangeCheck()) + Apply(settingsMode); + + // move into the m_Settings fields... + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + + serializedObject.ApplyModifiedProperties(); + } + + private void Apply(SettingsMode settingsMode) + { + switch (settingsMode) + { + case SettingsMode.Default: + Apply(ScreenSpaceReflection.SSRSettings.defaultSettings); + break; + case SettingsMode.HighQuality: + Apply(ScreenSpaceReflection.SSRSettings.highQualitySettings); + break; + case SettingsMode.Performance: + Apply(ScreenSpaceReflection.SSRSettings.performanceSettings); + break; + } + } + + private void Apply(ScreenSpaceReflection.SSRSettings settings) + { + var validTargets = targets.Where(x => x is ScreenSpaceReflection).Cast().ToArray(); + + Undo.RecordObjects(validTargets, "Apply SSR Settings"); + foreach (var validTarget in validTargets) + validTarget.settings = settings; + } + } +} diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta new file mode 100644 index 0000000..50e7bbc --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eb0236f80884a1f4793c96b4d2da5c68 +timeCreated: 1446039760 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta new file mode 100644 index 0000000..c1d5872 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a19e50b158b32e6458d43c13406863ff +folderAsset: yes +timeCreated: 1453972687 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc new file mode 100644 index 0000000..34b34ce --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc @@ -0,0 +1,265 @@ +/** +\author Michael Mara and Morgan McGuire, Casual Effects. 2015. +*/ + +#ifndef SCREEN_SPACE_RAYTRACE_INCLUDED +#define SCREEN_SPACE_RAYTRACE_INCLUDED + + +sampler2D_float _CameraDepthTexture; + + +float distanceSquared(float2 A, float2 B) { + A -= B; + return dot(A, A); +} + +float distanceSquared(float3 A, float3 B) { + A -= B; + return dot(A, A); +} + +void swap(inout float v0, inout float v1) { + float temp = v0; + v0 = v1; + v1 = temp; +} + + +bool isIntersecting(float rayZMin, float rayZMax, float sceneZ, float layerThickness) { + return (rayZMax >= sceneZ - layerThickness) && (rayZMin <= sceneZ); +} + +void rayIterations(in bool traceBehindObjects, inout float2 P, inout float stepDirection, inout float end, inout int stepCount, inout int maxSteps, inout bool intersecting, + inout float sceneZ, inout float2 dP, inout float3 Q, inout float3 dQ, inout float k, inout float dk, + inout float rayZMin, inout float rayZMax, inout float prevZMaxEstimate, inout bool permute, inout float2 hitPixel, + inout float2 invSize, inout float layerThickness) { + + bool stop = intersecting; + UNITY_LOOP + for (; + ( (P.x * stepDirection) <= end) && + (stepCount < maxSteps) && + (!stop); + P += dP, Q.z += dQ.z, k += dk, stepCount += 1) { + + // The depth range that the ray covers within this loop iteration. + // Assume that the ray is moving in increasing z and swap if backwards. + rayZMin = prevZMaxEstimate; + //rayZMin = (dQ.z * -0.5 + Q.z) / (dk * -0.5 + k); + // Compute the value at 1/2 pixel into the future + rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); + prevZMaxEstimate = rayZMax; + if (rayZMin > rayZMax) { swap(rayZMin, rayZMax); } + + // Undo the homogeneous operation to obtain the camera-space + // Q at each point + hitPixel = permute ? P.yx : P; + + sceneZ = tex2Dlod(_CameraDepthTexture, float4(hitPixel * invSize,0,0)).r; + sceneZ = -LinearEyeDepth(sceneZ); + + bool isBehind = (rayZMin <= sceneZ); + intersecting = isBehind && (rayZMax >= sceneZ - layerThickness); + stop = traceBehindObjects ? intersecting : isBehind; + + } // pixel on ray + P -= dP, Q.z -= dQ.z, k -= dk; +} + +/** + \param csOrigin must have z < -0.01, and project within the valid screen rectangle + \param stepRate Set to 1.0 by default, higher to step faster + */ +bool castDenseScreenSpaceRay + (float3 csOrigin, + float3 csDirection, + float4x4 projectToPixelMatrix, + float2 csZBufferSize, + float3 clipInfo, + float jitterFraction, + int maxSteps, + float layerThickness, + float maxRayTraceDistance, + out float2 hitPixel, + int stepRate, + bool refine, + bool traceBehindObjects, + out float3 csHitPoint, + out float stepCount) { + + float2 invSize = float2(1.0 / csZBufferSize.x, 1.0 / csZBufferSize.y); + + // Initialize to off screen + hitPixel = float2(-1, -1); + + float nearPlaneZ = -0.01; + // Clip ray to a near plane in 3D (doesn't have to be *the* near plane, although that would be a good idea) + float rayLength = ((csOrigin.z + csDirection.z * maxRayTraceDistance) > nearPlaneZ) ? + ((nearPlaneZ - csOrigin.z) / csDirection.z) : + maxRayTraceDistance; + + float3 csEndPoint = csDirection * rayLength + csOrigin; + + // Project into screen space + // This matrix has a lot of zeroes in it. We could expand + // out these multiplies to avoid multiplying by zero + // ...but 16 MADDs are not a big deal compared to what's ahead + float4 H0 = mul(projectToPixelMatrix, float4(csOrigin, 1.0)); + float4 H1 = mul(projectToPixelMatrix, float4(csEndPoint, 1.0)); + + // There are a lot of divisions by w that can be turned into multiplications + // at some minor precision loss...and we need to interpolate these 1/w values + // anyway. + // + // Because the caller was required to clip to the near plane, + // this homogeneous division (projecting from 4D to 2D) is guaranteed + // to succeed. + float k0 = 1.0 / H0.w; + float k1 = 1.0 / H1.w; + + // Screen-space endpoints + float2 P0 = H0.xy * k0; + float2 P1 = H1.xy * k1; + + // Switch the original points to values that interpolate linearly in 2D: + float3 Q0 = csOrigin * k0; + float3 Q1 = csEndPoint * k1; + +#if 1 // Clipping to the screen coordinates. We could simply modify maxSteps instead + float yMax = csZBufferSize.y - 0.5; + float yMin = 0.5; + float xMax = csZBufferSize.x - 0.5; + float xMin = 0.5; + + // 2D interpolation parameter + float alpha = 0.0; + // P0 must be in bounds + if (P1.y > yMax || P1.y < yMin) { + float yClip = (P1.y > yMax) ? yMax : yMin; + float yAlpha = (P1.y - yClip) / (P1.y - P0.y); // Denominator is not zero, since P0 != P1 (or P0 would have been clipped!) + alpha = yAlpha; + } + + // P0 must be in bounds + if (P1.x > xMax || P1.x < xMin) { + float xClip = (P1.x > xMax) ? xMax : xMin; + float xAlpha = (P1.x - xClip) / (P1.x - P0.x); // Denominator is not zero, since P0 != P1 (or P0 would have been clipped!) + alpha = max(alpha, xAlpha); + } + + // These are all in homogeneous space, so they interpolate linearly + P1 = lerp(P1, P0, alpha); + k1 = lerp(k1, k0, alpha); + Q1 = lerp(Q1, Q0, alpha); +#endif + + // We're doing this to avoid divide by zero (rays exactly parallel to an eye ray) + P1 = (distanceSquared(P0, P1) < 0.0001) ? P0 + float2(0.01, 0.01) : P1; + + float2 delta = P1 - P0; + + // Assume horizontal + bool permute = false; + if (abs(delta.x) < abs(delta.y)) { + // More-vertical line. Create a permutation that swaps x and y in the output + permute = true; + + // Directly swizzle the inputs + delta = delta.yx; + P1 = P1.yx; + P0 = P0.yx; + } + + // From now on, "x" is the primary iteration direction and "y" is the secondary one + + float stepDirection = sign(delta.x); + float invdx = stepDirection / delta.x; + float2 dP = float2(stepDirection, invdx * delta.y); + + // Track the derivatives of Q and k + float3 dQ = (Q1 - Q0) * invdx; + float dk = (k1 - k0) * invdx; + + dP *= stepRate; + dQ *= stepRate; + dk *= stepRate; + + P0 += dP * jitterFraction; + Q0 += dQ * jitterFraction; + k0 += dk * jitterFraction; + + // Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, and k from k0 to k1 + float3 Q = Q0; + float k = k0; + + // We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid + // voxels. Because the depth at -1/2 for a given pixel will be the same as at + // +1/2 for the previous iteration, we actually only have to compute one value + // per iteration. + float prevZMaxEstimate = csOrigin.z; + stepCount = 0.0; + float rayZMax = prevZMaxEstimate, rayZMin = prevZMaxEstimate; + float sceneZ = 100000; + + // P1.x is never modified after this point, so pre-scale it by + // the step direction for a signed comparison + float end = P1.x * stepDirection; + + bool intersecting = isIntersecting(rayZMin, rayZMax, sceneZ, layerThickness); + // We only advance the z field of Q in the inner loop, since + // Q.xy is never used until after the loop terminates + + //int rayIterations = min(maxSteps, stepsToGetOffscreen); + + + float2 P = P0; + + int originalStepCount = 0; + rayIterations(traceBehindObjects, P, stepDirection, end, originalStepCount, maxSteps, intersecting, + sceneZ, dP, Q, dQ, k, dk, + rayZMin, rayZMax, prevZMaxEstimate, permute, hitPixel, + invSize, layerThickness); + + + stepCount = originalStepCount; + if (refine && intersecting && stepRate > 1) { + + + // We're going back a step. + P -= dP, Q.z -= dQ.z, k -= dk; + prevZMaxEstimate = Q.z / k; + rayZMin = prevZMaxEstimate; + rayZMax = prevZMaxEstimate; + + intersecting = false; + int refinementStepCount = 0; + int refinementMaxSteps = stepRate; + + float refinementConstant = 1.0 / stepRate; + dQ.z *= refinementConstant; + dP *= refinementConstant; + dk *= refinementConstant; + + // Refinement + rayIterations(traceBehindObjects, P, stepDirection, end, refinementStepCount, refinementMaxSteps, intersecting, + sceneZ, dP, Q, dQ, k, dk, + rayZMin, rayZMax, prevZMaxEstimate, permute, hitPixel, + invSize, layerThickness); + stepCount += refinementStepCount * refinementConstant - 1.0; + //stepCount = refinementStepCount; + intersecting = true; + } + + + // Loop only advanced the Z component. Now that we know where we are going + // update xy + Q.xy += dQ.xy * stepCount; + // Q is a vector, so we are trying to get by with 1 division instead of 3. + csHitPoint = Q * (1.0 / k); + + return intersecting; +} + + +#endif // SCREEN_SPACE_RAYTRACE_INCLUDED diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta new file mode 100644 index 0000000..9b2d477 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6f70a4658ebf5f947abc302c6b49a6ba +timeCreated: 1449750676 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader new file mode 100644 index 0000000..7cbe318 --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader @@ -0,0 +1,1161 @@ +/** +\author Michael Mara and Morgan McGuire, Casual Effects. 2015. +*/ +Shader "Hidden/ScreenSpaceReflection" +{ + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + CGINCLUDE + + #include "UnityCG.cginc" + #include "UnityPBSLighting.cginc" + #include "UnityStandardBRDF.cginc" + #include "UnityStandardUtils.cginc" + #include "ScreenSpaceRaytrace.cginc" + + float4 _ProjInfo; + float4x4 _WorldToCameraMatrix; + float4x4 _CameraToWorldMatrix; + float4x4 _ProjectToPixelMatrix; + float2 _ScreenSize; + float2 _ReflectionBufferSize; + float2 _InvScreenSize; + float3 _CameraClipInfo; + + sampler2D _CameraGBufferTexture0; + sampler2D _CameraGBufferTexture1; + sampler2D _CameraGBufferTexture2; + sampler2D _CameraGBufferTexture3; + sampler2D _CameraReflectionsTexture; + + float _CurrentMipLevel; + float _RayStepSize; + float _MaxRayTraceDistance; + float _LayerThickness; + float _FresnelFade; + float _FresnelFadePower; + + + sampler2D _MainTex; + + int _VisualizeWhereBilateral; + int _EnableSSR; + int _DebugMode; + int _HalfResolution; + int _TreatBackfaceHitAsMiss; + int _AllowBackwardsRays; + int _TraceEverywhere; + + + // RG: SS Hitpoint of ray + // B: distance ray travelled, used for mip-selection in the final resolve + // A: confidence value + sampler2D _HitPointTexture; + sampler2D _FinalReflectionTexture; + + // RGB: camera-space normal (encoded in [0-1]) + // A: Roughness + sampler2D _NormalAndRoughnessTexture; + + float4 _MainTex_TexelSize; + float4 _SourceToTempUV; + + int _EnableRefine; + int _AdditiveReflection; + int _ImproveCorners; + + float _ScreenEdgeFading; + + float _MipBias; + + int _UseOcclusion; + + int _MaxSteps; + + int _FullResolutionFiltering; + + int _BilateralUpsampling; + + float _MaxRoughness; + float _RoughnessFalloffRange; + float _SSRMultiplier; + + float _FadeDistance; + + float _DistanceBlur; + + int _TraceBehindObjects; + int _FallbackToSky; + int _UseEdgeDetector; + int _HighlightSuppression; + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float _PixelsPerMeterAtOneMeter; + + int _UseAverageRayDistance; + sampler2D _AverageRayDistanceBuffer; + + // For temporal filtering: + float4x4 _CurrentCameraToPreviousCamera; + sampler2D _PreviousReflectionTexture; + sampler2D _PreviousCSZBuffer; + float _TemporalAlpha; + int _UseTemporalConfidence; + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; + }; + + v2f vert( appdata_img v ) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + o.uv2 = v.texcoord.xy; + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv2.y = 1-o.uv2.y; + #endif + return o; + } + + float2 mipToSize(int mip) { + return floor(_ReflectionBufferSize * exp2(-mip)); + } + + float3 ReconstructCSPosition(float2 S, float z) + { + float linEyeZ = -LinearEyeDepth(z); + return float3(( (( S.xy * _MainTex_TexelSize.zw) ) * _ProjInfo.xy + _ProjInfo.zw) * linEyeZ, linEyeZ); + } + + /** Read the camera-space position of the point at screen-space pixel ssP */ + float3 GetPosition(float2 ssP) { + float3 P; + + P.z = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, ssP.xy); + + // Offset to pixel center + P = ReconstructCSPosition(float2(ssP) /*+ float2(0.5, 0.5)*/, P.z); + return P; + } + + float square(float x) + { + return x*x; + } + + float applyEdgeFade(float2 tsP, float fadeStrength) { + float maxFade = 0.1; + + float2 itsP = float2(1.0, 1.0) - tsP; + float dist = min(min(itsP.x, itsP.y), min(tsP.x, tsP.x)); + float fade = dist / (maxFade*fadeStrength + 0.001); + fade = max(min(fade, 1.0), 0.0); + fade = pow(fade, 0.2); + return fade; + } + + float3 csMirrorVector(float3 csPosition, float3 csN) { + float3 csE = -normalize(csPosition.xyz); + float cos_o = dot(csN, csE); + float3 c_mi = normalize((csN * (2.0 * cos_o)) - csE); + return c_mi; + } + + + float4 fragRaytrace(v2f i, int stepRate) + { + float2 ssP = i.uv2.xy * _SourceToTempUV.zw; + float3 csPosition = GetPosition(ssP); + float smoothness = tex2D(_CameraGBufferTexture1, ssP).a; + if (csPosition.z < -100.0 || smoothness == 0.0) { + return float4(0.0,0.0,0.0,0.0); + } + + if ((!_TraceEverywhere) && (smoothness < (1.0 - _MaxRoughness)) ) { + return float4(0.0, 0.0, 0.0, 0.0); + } + + float3 wsNormal = tex2D(_CameraGBufferTexture2, ssP).rgb * 2.0 - 1.0; + + int2 ssC = int2(ssP * _ScreenSize); + + float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal); + float3 csRayDirection = csMirrorVector(csPosition, csN); + + if (_AllowBackwardsRays == 0 && csRayDirection.z > 0.0) { + return float4(0.0, 0.0, 0.0, 0.0); + } + + float maxRayTraceDistance = _MaxRayTraceDistance; + float jitterFraction = 0.0f; + float layerThickness = _LayerThickness; + + int maxSteps = _MaxSteps; + // Bump the ray more in world space as it gets farther away (and so each pixel covers more WS distance) + float rayBump = max(-0.01*csPosition.z, 0.001); + float2 hitPixel; + float3 csHitPoint; + float stepCount; + + bool wasHit = castDenseScreenSpaceRay + (csPosition + (csN) * rayBump, + csRayDirection, + _ProjectToPixelMatrix, + _ScreenSize, + _CameraClipInfo, + jitterFraction, + maxSteps, + layerThickness, + maxRayTraceDistance, + hitPixel, + stepRate, + _EnableRefine == 1, + _TraceBehindObjects == 1, + csHitPoint, + stepCount); + + float2 tsPResult = hitPixel / _ScreenSize; + float rayDist = dot(csHitPoint - csPosition, csRayDirection); + float confidence = 0.0; + if (wasHit) { + confidence = square(1.0 - max(2.0*float(stepCount) / float(maxSteps) - 1.0, 0.0)); + confidence *= clamp(((_MaxRayTraceDistance - rayDist) / _FadeDistance), 0.0, 1.0); + // Fake fresnel fade + float3 csE = -normalize(csPosition.xyz); + confidence *= max(0.0, lerp(pow(abs(dot(csRayDirection, -csE)), _FresnelFadePower), 1, 1.0 - _FresnelFade)); + if (_TreatBackfaceHitAsMiss > 0) { + float3 wsHitNormal = tex2Dlod(_CameraGBufferTexture2, float4(tsPResult, 0, 0)).rgb * 2.0 - 1.0; + float3 wsRayDirection = mul(_CameraToWorldMatrix, float4(csRayDirection, 0)).xyz; + if (dot(wsHitNormal, wsRayDirection) > 0) { + confidence = 0.0; + } + } + } else if (_FallbackToSky > 0) { + float sceneZ = tex2Dlod(_CameraDepthTexture, float4(tsPResult, 0, 0)).r; + sceneZ = -LinearEyeDepth(sceneZ); + if (sceneZ < -1000) { // 1km ~= infinity + confidence = 1.0; + } + } + + // Fade out reflections that hit near edge of screen, to prevent abrupt appearance/disappearance when object go off screen + // Fade out reflections that hit near edge of screen, + // to prevent abrupt appearance/disappearance when object go off screen + float vignette = applyEdgeFade(tsPResult, _ScreenEdgeFading); + confidence *= vignette; + confidence *= vignette; + + + return float4(tsPResult, rayDist, confidence); + } + + float4 fragComposite(v2f i) : SV_Target + { + // Pixel being shaded + float2 tsP = i.uv2.xy; + + // View space point being shaded + float3 C = GetPosition(tsP); + + // Final image before this pass + float4 gbuffer3 = tex2D(_MainTex, i.uv); + + float4 specEmission = float4(0.0,0.0,0.0,0.0); + float3 specColor = tex2D(_CameraGBufferTexture1, tsP).rgb; + + float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP).a; + + float4 reflectionTexel = tex2D(_FinalReflectionTexture, tsP * _SourceToTempUV.xy); + + float4 gbuffer0 = tex2D(_CameraGBufferTexture0, tsP); + // Let core Unity functions do the dirty work of applying the BRDF + float3 baseColor = gbuffer0.rgb; + float occlusion = gbuffer0.a; + float oneMinusReflectivity; + baseColor = EnergyConservationBetweenDiffuseAndSpecular(baseColor, specColor, oneMinusReflectivity); + + float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0; + + float3 csEyeVec = normalize(C); + float3 eyeVec = mul(_CameraToWorldMatrix, float4(csEyeVec, 0)).xyz; + + float3 worldPos = mul(_CameraToWorldMatrix, float4(C, 1)).xyz; + + float cos_o = dot(wsNormal, eyeVec); + float3 w_mi = -normalize((wsNormal * (2.0 * cos_o)) - eyeVec); + + + float3 incomingRadiance = reflectionTexel.rgb; + + UnityLight light; + light.color = 0; + light.dir = 0; + light.ndotl = 0; + + UnityIndirect ind; + ind.diffuse = 0; + ind.specular = incomingRadiance; + + float3 ssrResult = UNITY_BRDF_PBS (0, specColor, oneMinusReflectivity, 1-roughness, wsNormal, -eyeVec, light, ind).rgb * _SSRMultiplier; + float confidence = reflectionTexel.a; + + if(_EnableSSR == 0) { + confidence = 0.0; + } + + specEmission.rgb = tex2D(_CameraReflectionsTexture, tsP).rgb; + float3 finalGlossyTerm; + // Subtract out Unity's glossy result: (we're just applying the delta) + if (_AdditiveReflection == 0) { + gbuffer3 -= specEmission; + // We may have blown out our dynamic range by adding then subtracting the reflection probes. + // As a half-measure to fix this, simply clamp to zero + gbuffer3 = max(gbuffer3, 0); + finalGlossyTerm = lerp(specEmission.rgb, ssrResult, saturate(confidence)); + } else { + finalGlossyTerm = ssrResult*saturate(confidence); + } + if (_UseOcclusion) { + finalGlossyTerm *= occlusion; + } + + if (_DebugMode == 1) + return float4(incomingRadiance,0); + if (_DebugMode == 2) + return float4(ssrResult,0); + if (_DebugMode == 3) + return float4(finalGlossyTerm,0); + if (_DebugMode == 4) + return confidence; + if (_DebugMode == 5) + return roughness; + if (_DebugMode == 6) + return float4(baseColor,0); + if (_DebugMode == 7) + return float4(specColor,0); + if (_DebugMode == 8) + return 1.0-oneMinusReflectivity; + if (_DebugMode == 9) + return float4(specEmission.rgb,0); + if (_DebugMode == 10) + return float4(specEmission.rgb-ssrResult,0); + if (_DebugMode == 11) + return float4(ssrResult-specEmission.rgb,0); + if (_DebugMode == 12) + return gbuffer3; + if (_DebugMode == 13) + return -float4(gbuffer3.rgb, 0.0); + if (_DebugMode == 14) // Mip level, stored directly in ssrResult + return float4(incomingRadiance, 0); + + // Additively blend the glossy GI result with the output buffer + return gbuffer3 + float4(finalGlossyTerm, 0); + } + + float roughnessWeight(float midpointRoughness, float tapRoughness) { + return (1.0 - sqrt(sqrt(abs(midpointRoughness-tapRoughness)))); + } + + float normalWeight(float3 midpointNormal, float3 tapNormal) { + return clamp(dot(midpointNormal, tapNormal), 0, 1); + } + + float highlightDecompression(float x) { + return x / (1.0 - x); + } + + float3 highlightDecompression(float3 x) { + return float3( + highlightDecompression(x.x), + highlightDecompression(x.y), + highlightDecompression(x.z)); + } + + float highlightCompression(float x) { + return x / (1.0 + x); + } + + float3 highlightCompression(float3 x) { + return float3( + highlightCompression(x.x), + highlightCompression(x.y), + highlightCompression(x.z)); + } + + float4 _Axis; + float4 fragGBlur(v2f i) : SV_Target + { + int radius = 4; + // Pixel being shaded + float2 tsP = i.uv2.xy; + float weightSum = 0.0; + float gaussWeights[5] = {0.225, 0.150, 0.110, 0.075, 0.0525};//{0.225, 0.150, 0.110, 0.075, 0.0525}; + float4 resultSum = float4(0.0, 0.0, 0.0, 0.0); + float4 unweightedResultSum = float4(0.0, 0.0, 0.0, 0.0); + float4 nAndRough = tex2D(_NormalAndRoughnessTexture, tsP); + float midpointRoughness = nAndRough.a; + float3 midpointNormal = nAndRough.rgb * 2 - 1; + if (_FullResolutionFiltering) { + for (int i = -2*radius; i <= 2*radius; ++i) { + float4 temp; + float tapRoughness = midpointRoughness; + float3 tapNormal = midpointNormal; + float2 tsTap = tsP + (_Axis.xy * _MainTex_TexelSize.xy * float2(i,i)); + + temp = tex2D(_MainTex, tsTap); + + int gaussWeightIndex; + #if defined(UNITY_COMPILER_HLSL) && !defined(SHADER_API_D3D9) + gaussWeightIndex = abs(i) >> 1; // We purposefully do integer division, but that does not compile on hlsl2glsl + #else + gaussWeightIndex = frac(abs(i) / 2); + #endif + + float weight = temp.a * gaussWeights[gaussWeightIndex]*0.5; + // Bilateral filtering + if (_ImproveCorners) { + nAndRough = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = nAndRough.a; + tapNormal = nAndRough.rgb * 2 - 1; + weight *= normalWeight(midpointNormal, tapNormal); + } + weightSum += weight; + resultSum += temp*weight; + unweightedResultSum += temp; + } + } else { + for (int i = -radius; i <= radius; ++i) { + float4 temp; + float tapRoughness; + float3 tapNormal; + float2 tsTap = tsP + (_Axis.xy * _MainTex_TexelSize.xy * float2(i,i)*2.0); + + temp = tex2D(_MainTex, tsTap); + + float weight = temp.a * gaussWeights[abs(i)]; + // Bilateral filtering + if (_ImproveCorners) { + nAndRough = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = nAndRough.a; + tapNormal = nAndRough.rgb * 2 - 1; + weight *= normalWeight(midpointNormal, tapNormal); + } + weightSum += weight; + if (_HighlightSuppression) { + temp.rgb = highlightCompression(temp.rgb); + } + unweightedResultSum += temp; + resultSum += temp*weight; + } + } + + if (weightSum > 0.01) { + float invWeightSum = (1.0/weightSum); + // Adding the sqrt seems to decrease temporal flickering at the expense + // of having larger "halos" of fallback on rough surfaces + // Subject to change with testing. Sqrt around only half the expression is *intentional*. + float confidence = min(resultSum.a * sqrt(max(invWeightSum, 2.0)), 1.0); + float3 finalColor = resultSum.rgb * invWeightSum; + if (_HighlightSuppression) { + finalColor = highlightDecompression(finalColor); + } + return float4(finalColor, confidence); + } else { + float3 finalColor = unweightedResultSum.rgb / (2 * radius + 1); + if (_HighlightSuppression) { + finalColor = highlightDecompression(finalColor); + } + return float4(finalColor, 0.0); + } + } + + sampler2D _ReflectionTexture0; + sampler2D _ReflectionTexture1; + sampler2D _ReflectionTexture2; + sampler2D _ReflectionTexture3; + sampler2D _ReflectionTexture4; + // Simulate mip maps, since we don't have NPOT mip-chains + float4 getReflectionValue(float2 tsP, int mip) { + float4 coord = float4(tsP,0,0); + if (mip == 0) { + return tex2Dlod(_ReflectionTexture0, coord); + } else if (mip == 1) { + return tex2Dlod(_ReflectionTexture1, coord); + } else if (mip == 2) { + return tex2Dlod(_ReflectionTexture2, coord); + } else if (mip == 3) { + return tex2Dlod(_ReflectionTexture3, coord); + } else { + return tex2Dlod(_ReflectionTexture4, coord); + } + } + + sampler2D _EdgeTexture0; + sampler2D _EdgeTexture1; + sampler2D _EdgeTexture2; + sampler2D _EdgeTexture3; + sampler2D _EdgeTexture4; + // Simulate mip maps, since we don't have NPOT mip-chains + float4 getEdgeValue(float2 tsP, int mip) { + float4 coord = float4(tsP + float2(1.0/(2 * mipToSize(mip))),0,0); + if (mip == 0) { + return tex2Dlod(_EdgeTexture0, coord); + } else if (mip == 1) { + return tex2Dlod(_EdgeTexture1, coord); + } else if (mip == 2) { + return tex2Dlod(_EdgeTexture2, coord); + } else if (mip == 3) { + return tex2Dlod(_EdgeTexture3, coord); + } else { + return tex2Dlod(_EdgeTexture4, coord); + } + } + + float2 centerPixel(float2 inputP) { + return floor(inputP - float2(0.5,0.5)) + float2(0.5,0.5); + } + + float2 snapToTexelCenter(float2 inputP, float2 texSize, float2 texSizeInv) { + return centerPixel(inputP * texSize) * texSizeInv; + } + + float4 bilateralUpsampleReflection(float2 tsP, int mip) { + + float2 smallTexSize = mipToSize(mip); + float2 smallPixelPos = tsP * smallTexSize; + float2 smallPixelPosi = centerPixel(smallPixelPos); + float2 smallTexSizeInv = 1.0 / smallTexSize; + + + float2 p0 = smallPixelPosi * smallTexSizeInv; + float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv; + float2 p1 = float2(p3.x, p0.y); + float2 p2 = float2(p0.x, p3.y); + + float4 V0 = getReflectionValue(p0.xy, mip); + float4 V1 = getReflectionValue(p1.xy, mip); + float4 V2 = getReflectionValue(p2.xy, mip); + float4 V3 = getReflectionValue(p3.xy, mip); + + float a0 = 1.0; + float a1 = 1.0; + float a2 = 1.0; + float a3 = 1.0; + + // Bilateral weights: + // Bilinear interpolation (filter distance) + float2 smallPixelPosf = smallPixelPos - smallPixelPosi; + a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y); + a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y); + a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y; + a3 = smallPixelPosf.x * smallPixelPosf.y; + + float2 fullTexSize = _ReflectionBufferSize; + float2 fullTexSizeInv = 1.0 / fullTexSize; + + float4 hiP0 = float4(snapToTexelCenter(p0, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP3 = float4(snapToTexelCenter(p3, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP1 = float4(snapToTexelCenter(p1, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP2 = float4(snapToTexelCenter(p2, fullTexSize, fullTexSizeInv), 0,0); + + float4 tempCenter = tex2Dlod(_NormalAndRoughnessTexture, float4(tsP, 0, 0)); + float3 n = tempCenter.xyz * 2 - 1; + + float4 temp0 = tex2Dlod(_NormalAndRoughnessTexture, hiP0); + float4 temp1 = tex2Dlod(_NormalAndRoughnessTexture, hiP1); + float4 temp2 = tex2Dlod(_NormalAndRoughnessTexture, hiP2); + float4 temp3 = tex2Dlod(_NormalAndRoughnessTexture, hiP3); + + float3 n0 = temp0.xyz * 2 - 1; + float3 n1 = temp1.xyz * 2 - 1; + float3 n2 = temp2.xyz * 2 - 1; + float3 n3 = temp3.xyz * 2 - 1; + + a0 *= normalWeight(n, n0); + a1 *= normalWeight(n, n1); + a2 *= normalWeight(n, n2); + a3 *= normalWeight(n, n3); + + float r = tempCenter.a; + float r0 = temp0.a; + float r1 = temp1.a; + float r2 = temp2.a; + float r3 = temp3.a; + + + a0 *= roughnessWeight(r, r0); + a1 *= roughnessWeight(r, r1); + a2 *= roughnessWeight(r, r2); + a3 *= roughnessWeight(r, r3); + + // Slightly offset from zero + a0 = max(a0, 0.001); + a1 = max(a1, 0.001); + a2 = max(a2, 0.001); + a3 = max(a3, 0.001); + + // Nearest neighbor + // a0 = a1 = a2 = a3 = 1.0; + + // Normalize the blending weights (weights were chosen so that + // the denominator can never be zero) + float norm = 1.0 / (a0 + a1 + a2 + a3); + + // Blend + float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3) * norm; + //return V0; + return value; + } + + /** Explicit bilinear fetches; must be used if the reflection buffer is bound using point sampling */ + float4 bilinearUpsampleReflection(float2 tsP, int mip) { + + float2 smallTexSize = mipToSize(mip); + float2 smallPixelPos = tsP * smallTexSize; + float2 smallPixelPosi = centerPixel(smallPixelPos); + float2 smallTexSizeInv = 1.0 / smallTexSize; + + + float2 p0 = smallPixelPosi * smallTexSizeInv; + float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv; + float2 p1 = float2(p3.x, p0.y); + float2 p2 = float2(p0.x, p3.y); + + float4 V0 = getReflectionValue(p0.xy, mip); + float4 V1 = getReflectionValue(p1.xy, mip); + float4 V2 = getReflectionValue(p2.xy, mip); + float4 V3 = getReflectionValue(p3.xy, mip); + + float a0 = 1.0; + float a1 = 1.0; + float a2 = 1.0; + float a3 = 1.0; + + // Bilateral weights: + // Bilinear interpolation (filter distance) + float2 smallPixelPosf = smallPixelPos - smallPixelPosi; + a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y); + a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y); + a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y; + a3 = smallPixelPosf.x * smallPixelPosf.y; + + // Blend + float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3); + return value; + } + + // Unity's roughness is GGX roughness squared + float roughnessToBlinnPhongExponent(float roughness) { + float r2 = roughness*roughness; + return 2.0f / r2*r2 - 2.0f; + } + + float glossyLobeSlope(float roughness) { + return pow(roughness, 4.0/3.0); + } + + + // Empirically based on our filter: + // Mip | Pixels + // -------------- + // 0 | 1 no filter, so single pixel + // 1 | 17 2r + 1 filter applied once, grabbing from pixels r away in either direction (r=8, four samples times stride of 2) + // 2 | 50 2r + 1 filter applied on double size pixels, and each of those pixels had reached another r out to the side 2(2r + 1) + m_1 + // 3 | 118 4(2r + 1) + m_2 + // 4 | 254 8(2r + 1) + m_3 + // + // Approximated by pixels = 16*2^mip-15 + // rearranging we get mip = log_2((pixels + 15) / 16) + // + float filterFootprintInPixelsToMip(float footprint) { + return log2((footprint + 15) / 16); + } + + float3 ansiGradient(float t) { + //return float3(t, t, t); + return fmod(floor(t * float3(8.0, 4.0, 2.0)), 2.0); + } + + float4 fragCompositeSSR(v2f i) : SV_Target + { + // Pixel being shaded + float2 tsP = i.uv2.xy; + + float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP * _SourceToTempUV.zw).a; + + float rayDistance = 0.0; + if (_UseAverageRayDistance) { + rayDistance = tex2D(_AverageRayDistanceBuffer, tsP).r; + } else { + rayDistance = tex2D(_HitPointTexture, tsP).z; + } + + // Get the camera space position of the reflection hit + float3 csPosition = GetPosition(tsP); + float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0; + float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal); + float3 c_mi = csMirrorVector(csPosition, csN); + float3 csHitpoint = c_mi * rayDistance + csPosition; + + + float gatherFootprintInMeters = glossyLobeSlope(roughness) * rayDistance; + // We could add a term that incorporates the normal + // This approximation assumes reflections happen at a glancing angle + float filterFootprintInPixels = gatherFootprintInMeters * _PixelsPerMeterAtOneMeter / csHitpoint.z; + if (_HalfResolution == 1) { + filterFootprintInPixels *= 0.5; + } + + float mip = filterFootprintInPixelsToMip(filterFootprintInPixels); + + float nonPhysicalMip = pow(roughness, 3.0 / 4.0) * UNITY_SPECCUBE_LOD_STEPS; + + if (_HalfResolution == 1) { + nonPhysicalMip = nonPhysicalMip * 0.7; + } + mip = lerp(nonPhysicalMip, mip, _DistanceBlur); + mip = max(0, min(4, mip + _MipBias)); + + if (_DebugMode == 14) { + return float4(ansiGradient(mip*0.25), 1.0); + } + + float4 result; + { + int mipMin = int(mip); + int mipMax = min(mipMin + 1, 4); + float mipLerp = mip-mipMin; + + if (_BilateralUpsampling == 1) { + if (_UseEdgeDetector == 1) { + float nonEdginess = lerp(getEdgeValue(tsP, mipMin), + getEdgeValue(tsP, mipMax), mipLerp); + if (nonEdginess < 0.9) { + result = lerp(bilateralUpsampleReflection(tsP, mipMin), bilateralUpsampleReflection(tsP, mipMax), mipLerp); + if (_VisualizeWhereBilateral == 1) { + result = float4(1, 0, 0, 0); + } + } else { + result = lerp(bilinearUpsampleReflection(tsP, mipMin), bilinearUpsampleReflection(tsP, mipMax), mipLerp); + } + } else { + result = lerp(bilateralUpsampleReflection(tsP, mipMin), bilateralUpsampleReflection(tsP, mipMax), mipLerp); + } + } else { + float4 minResult = getReflectionValue(tsP, mipMin); + float4 maxResult = getReflectionValue(tsP, mipMax); + result = lerp(minResult, maxResult, mipLerp); + result.a = min(minResult.a, maxResult.a); + } + } + + result.a = min(result.a, 1.0); + float vignette = applyEdgeFade(tsP, _ScreenEdgeFading); + result.a *= vignette; + + + float alphaModifier = 1.0 - clamp((roughness - (_MaxRoughness - _RoughnessFalloffRange)) / _RoughnessFalloffRange, 0.0, 1.0); + result.a *= alphaModifier; + return result; + } + + float4 fragBlit(v2f i) : SV_Target + { + // Pixel being shaded + float2 ssP = i.uv2.xy; + return tex2D(_MainTex, ssP); + + } + + float edgeDetector(float2 tsP, float2 axis, float2 texelSize) { + float4 temp = tex2D(_NormalAndRoughnessTexture, tsP); + float midpointRoughness = temp.a; + float3 midpointNormal = temp.rgb * 2 - 1; + + float tapRoughness; + float3 tapNormal; + float2 tsTap = tsP + (axis * _MainTex_TexelSize.xy); + + temp = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = temp.a; + tapNormal = temp.rgb * 2 - 1; + + float weight = 1.0; + weight *= roughnessWeight(midpointRoughness, tapRoughness); + weight *= normalWeight(midpointNormal, tapNormal); + + return weight; + } + + + float4 fragEdge(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + return edgeDetector(tsP, float2(1,0), _MainTex_TexelSize.xy) * edgeDetector(tsP, float2(0,1), _MainTex_TexelSize.xy); + } + + int _LastMip; + float4 fragMin(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float2 lastTexSize = mipToSize(_LastMip); + float2 lastTexSizeInv = 1.0 / lastTexSize;//_SourceToTempUV.xy * exp2(mip); + float2 p00 = snapToTexelCenter(tsP, lastTexSize, lastTexSizeInv); + float2 p11 = p00 + lastTexSizeInv; + return min( + min(tex2D(_MainTex, p00), tex2D(_MainTex, p11)), + min(tex2D(_MainTex, float2(p00.x, p11.y)), tex2D(_MainTex, float2(p11.x, p00.y))) + ); + } + + float4 fragResolveHitPoints(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float4 temp = tex2D(_HitPointTexture, tsP); + float2 hitPoint = temp.xy; + float confidence = temp.w; + float3 colorResult = confidence > 0.0 ? + tex2D(_MainTex, hitPoint).rgb : + tex2D(_CameraReflectionsTexture, tsP).rgb; + +#ifdef UNITY_COMPILER_HLSL + if (any(isnan(colorResult))) + colorResult = float3(0.0, 0.0, 0.0); + // As of 11/29/2015, on Unity 5.3 on a Windows 8.1 computer with a NVIDIA GeForce 980, + // with driver 347.62, the above check does not actually work to get rid of NaNs! + // So we add this "redundant" check. + if (!all(isfinite(colorResult))) + colorResult = float3(0.0, 0.0, 0.0); +#endif + + return float4(colorResult, confidence); + } + + float4 fragBilatKeyPack(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float3 csN = tex2D(_CameraGBufferTexture2, tsP).xyz; + float roughness = tex2D(_CameraGBufferTexture1, tsP).a; + return float4(csN, roughness); + } + + float4 fragDepthToCSZ(v2f i) : SV_Target + { + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv2.xy); + return float4(-LinearEyeDepth(depth), 0.0, 0.0, 0.0); + } + + + float3 csPositionToOldNormalizedScreenCoordinate(float3 csPosition) + { + // We could multiply these matrices together on the CPU + float4 oldCSPosition = mul(_CurrentCameraToPreviousCamera, float4(csPosition, 1.0)); + float4 oldSSCoordinate = mul(_ProjectToPixelMatrix, oldCSPosition); + return float3((oldSSCoordinate.xy / oldSSCoordinate.w) * _InvScreenSize, oldCSPosition.z); + } + + float4 fragTemporalFilter(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, tsP); + float3 csPosition = GetPosition(tsP); + + float rayDistance = 0.0; + if (_UseAverageRayDistance) { + rayDistance = tex2D(_AverageRayDistanceBuffer, tsP).r; + } else { + rayDistance = tex2D(_HitPointTexture, tsP).b; + } + + // Virtual is the physics sense, not the other 20+ interpretations in CG + float3 virtualReflectionCSPosition = normalize(csPosition) * rayDistance + csPosition; + + float3 oldTSP = csPositionToOldNormalizedScreenCoordinate(csPosition); + float3 oldVirtualReflectionTSP = csPositionToOldNormalizedScreenCoordinate(virtualReflectionCSPosition); + + float oldCSZ = tex2D(_PreviousCSZBuffer, oldTSP.xy); + float4 currentResult = tex2D(_FinalReflectionTexture, tsP); + float4 oldResult = tex2D(_PreviousReflectionTexture, oldVirtualReflectionTSP.xy); + + float zError = abs(oldCSZ - oldTSP.z); + // Start knocking down contribution at 5cm error, go to 0 at 5 more cm later + float fallbackStart = 0.05; + float fallbackEnd = 0.05; + float zAlphaModifier = 1.0 - clamp((zError - fallbackStart) * (1.0 / fallbackEnd), 0.0, 1.0); + + float alpha = _TemporalAlpha; + alpha *= zAlphaModifier; + + if (_UseTemporalConfidence) { + alpha *= oldResult.w; + } + + // Always compress + currentResult.rgb = highlightCompression(currentResult.rgb); + oldResult.rgb = highlightCompression(oldResult.rgb); + + float4 resultValue = lerp(currentResult, oldResult, alpha); + + resultValue.rgb = highlightDecompression(resultValue.rgb); + + + return resultValue; + + } + + + float4 fragAverageRayDistance(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + + float sumRayDistance = tex2D(_HitPointTexture, tsP).b; + float sumWeight = 1.0; + + float roughness = 1.0 - tex2D(_CameraGBufferTexture1, tsP).a; + float step = roughness * 3.0; + /* + for (float x = -step; x < step; x += 2 * step) { + for (float y = -step; y < step; y += 2 * step) { + float weight = 0.5; + sumRayDistance += weight * tex2D(_HitPointTexture, (float2(x,y) * _InvScreenSize) + tsP).b; + sumWeight += weight; + } + } + */ + return float4(sumRayDistance / sumWeight, 0.0, 0.0, 0.0); + } + + static const int NUM_POISSON_TAPS = 12; + // Same as used in CameraMotionBlur.shader + static const float2 poissonSamples[NUM_POISSON_TAPS] = + { + float2(-0.326212,-0.40581), + float2(-0.840144,-0.07358), + float2(-0.695914,0.457137), + float2(-0.203345,0.620716), + float2(0.96234,-0.194983), + float2(0.473434,-0.480026), + float2(0.519456,0.767022), + float2(0.185461,-0.893124), + float2(0.507431,0.064425), + float2(0.89642,0.412458), + float2(-0.32194,-0.932615), + float2(-0.791559,-0.59771) + }; + + float4 fragFilterSharpReflections(v2f i) : SV_Target + { + // Could improve perf by not computing blur when we won't be sampling the highest level anyways + float2 tsP = i.uv2.xy; + float4 sum = 0.0; + float sampleRadius = _MainTex_TexelSize.xy * 2.0; + for (int i = 0; i < NUM_POISSON_TAPS; i++) { + float2 p = tsP + poissonSamples[i] * sampleRadius; + float4 tap = tex2Dlod(_MainTex, float4(p, 0, 0)); + if (_HighlightSuppression) { + tap.rgb = highlightCompression(tap.rgb); + } + sum += tap; + } + float4 result = sum / float(NUM_POISSON_TAPS); + if (_HighlightSuppression) { + result.rgb = highlightDecompression(result.rgb); + } + return result; + + } + + ENDCG + +SubShader { + + ZTest Always Cull Off ZWrite Off + + // 0: Raytrace, step size 1 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace1 + #pragma target 3.0 + float4 fragRaytrace1(v2f i) : SV_Target { return fragRaytrace(i, 1); } + ENDCG + } + + // 1: Raytrace, step size 2 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace2 + #pragma target 3.0 + float4 fragRaytrace2(v2f i) : SV_Target { return fragRaytrace(i, 2); } + ENDCG + } + + // 2: Raytrace, step size 4 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace4 + #pragma target 3.0 + float4 fragRaytrace4(v2f i) : SV_Target { return fragRaytrace(i, 4); } + ENDCG + } + + // 3: Raytrace, step size 8 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace8 + #pragma target 3.0 + float4 fragRaytrace8(v2f i) : SV_Target { return fragRaytrace(i, 8); } + ENDCG + } + + // 4: Raytrace, step size 16 + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace16 + #pragma target 3.0 + float4 fragRaytrace16(v2f i) : SV_Target { return fragRaytrace(i, 16); } + ENDCG + } + + // 5: Composite + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragComposite + #pragma target 3.0 + ENDCG + } + + // 6: GBlur + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragGBlur + #pragma target 3.0 + ENDCG + } + + // 7: CompositeSSR + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragCompositeSSR + #pragma target 3.0 + ENDCG + } + + // 8: Simple Blit + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragBlit + #pragma target 3.0 + ENDCG + } + + // 9: Generate Edge Texture + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragEdge + #pragma target 3.0 + ENDCG + } + + // 10: Min mip generation + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragMin + #pragma target 3.0 + ENDCG + } + + // 11: Hit point texture to reflection buffer + Pass { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragResolveHitPoints + #pragma target 3.0 + ENDCG + } + + // 12: Pack Bilateral Filter Keys in single buffer + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragBilatKeyPack + #pragma target 3.0 + ENDCG + } + + // 13: Blit depth information as camera space Z + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragDepthToCSZ + #pragma target 3.0 + ENDCG + } + + // 14: Temporally filter buffer + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragTemporalFilter + #pragma target 3.0 + ENDCG + } + + // 15: Generate average ray distance + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragAverageRayDistance + #pragma target 3.0 + ENDCG + } + + // 16: Filter the highest quality reflection buffer + Pass{ + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragFilterSharpReflections + #pragma target 3.0 + ENDCG + } + +} + +Fallback off + +} diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta new file mode 100644 index 0000000..f6718fe --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7e2fcc83af19e744787647ec0ac5d42c +timeCreated: 1449750821 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs new file mode 100644 index 0000000..7cecf5e --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs @@ -0,0 +1,716 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Rendering/Screen Space Reflection")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class ScreenSpaceReflection : MonoBehaviour + { + public enum SSRDebugMode + { + None = 0, + IncomingRadiance = 1, + SSRResult = 2, + FinalGlossyTerm = 3, + SSRMask = 4, + Roughness = 5, + BaseColor = 6, + SpecColor = 7, + Reflectivity = 8, + ReflectionProbeOnly = 9, + ReflectionProbeMinusSSR = 10, + SSRMinusReflectionProbe = 11, + NoGlossy = 12, + NegativeNoGlossy = 13, + MipLevel = 14, + } + + public enum SSRResolution + { + FullResolution = 0, + HalfTraceFullResolve = 1, + HalfResolution = 2, + } + + [Serializable] + public struct SSRSettings + { + [AttributeUsage(AttributeTargets.Field)] + public class LayoutAttribute : PropertyAttribute + {} + + [Layout] + public BasicSettings basicSettings; + + [Layout] + public ReflectionSettings reflectionSettings; + + [Layout] + public AdvancedSettings advancedSettings; + + [Layout] + public DebugSettings debugSettings; + + private static readonly SSRSettings s_Performance = new SSRSettings + { + basicSettings = new BasicSettings + { + screenEdgeFading = 0, + maxDistance = 10.0f, + fadeDistance = 10.0f, + reflectionMultiplier = 1.0f, + enableHDR = false, + additiveReflection = false + }, + reflectionSettings = new ReflectionSettings + { + maxSteps = 64, + rayStepSize = 4, + widthModifier = 0.5f, + smoothFallbackThreshold = 0.4f, + distanceBlur = 1.0f, + fresnelFade = 0.2f, + fresnelFadePower = 2.0f, + smoothFallbackDistance = 0.05f, + }, + advancedSettings = new AdvancedSettings + { + useTemporalConfidence = false, + temporalFilterStrength = 0.0f, + treatBackfaceHitAsMiss = false, + allowBackwardsRays = false, + traceBehindObjects = true, + highQualitySharpReflections = false, + traceEverywhere = false, + resolution = SSRResolution.HalfResolution, + bilateralUpsample = false, + improveCorners = false, + reduceBanding = false, + highlightSuppression = false + }, + debugSettings = new DebugSettings + { + debugMode = SSRDebugMode.None + } + }; + + private static readonly SSRSettings s_Default = new SSRSettings + { + basicSettings = new BasicSettings + { + screenEdgeFading = 0.03f, + maxDistance = 100.0f, + fadeDistance = 100.0f, + reflectionMultiplier = 1.0f, + enableHDR = true, + additiveReflection = false, + }, + reflectionSettings = new ReflectionSettings + { + maxSteps = 128, + rayStepSize = 3, + widthModifier = 0.5f, + smoothFallbackThreshold = 0.2f, + distanceBlur = 1.0f, + fresnelFade = 0.2f, + fresnelFadePower = 2.0f, + smoothFallbackDistance = 0.05f, + }, + advancedSettings = new AdvancedSettings + { + useTemporalConfidence = true, + temporalFilterStrength = 0.7f, + treatBackfaceHitAsMiss = false, + allowBackwardsRays = false, + traceBehindObjects = true, + highQualitySharpReflections = true, + traceEverywhere = true, + resolution = SSRResolution.HalfTraceFullResolve, + bilateralUpsample = true, + improveCorners = true, + reduceBanding = true, + highlightSuppression = false + }, + debugSettings = new DebugSettings + { + debugMode = SSRDebugMode.None + } + }; + + private static readonly SSRSettings s_HighQuality = new SSRSettings + { + basicSettings = new BasicSettings + { + screenEdgeFading = 0.03f, + maxDistance = 100.0f, + fadeDistance = 100.0f, + reflectionMultiplier = 1.0f, + enableHDR = true, + additiveReflection = false, + }, + reflectionSettings = new ReflectionSettings + { + maxSteps = 512, + rayStepSize = 1, + widthModifier = 0.5f, + smoothFallbackThreshold = 0.2f, + distanceBlur = 1.0f, + fresnelFade = 0.2f, + fresnelFadePower = 2.0f, + smoothFallbackDistance = 0.05f, + }, + advancedSettings = new AdvancedSettings + { + useTemporalConfidence = true, + temporalFilterStrength = 0.7f, + treatBackfaceHitAsMiss = false, + allowBackwardsRays = false, + traceBehindObjects = true, + highQualitySharpReflections = true, + traceEverywhere = true, + resolution = SSRResolution.HalfTraceFullResolve, + bilateralUpsample = true, + improveCorners = true, + reduceBanding = true, + highlightSuppression = false + }, + debugSettings = new DebugSettings + { + debugMode = SSRDebugMode.None + } + }; + + + public static SSRSettings performanceSettings + { + get { return s_Performance; } + } + + public static SSRSettings defaultSettings + { + get { return s_Default; } + } + + public static SSRSettings highQualitySettings + { + get { return s_HighQuality; } + } + } + + [Serializable] + public struct BasicSettings + { + /// BASIC SETTINGS + [Tooltip("Nonphysical multiplier for the SSR reflections. 1.0 is physically based.")] + [Range(0.0f, 2.0f)] + public float reflectionMultiplier; + + [Tooltip("Maximum reflection distance in world units.")] + [Range(0.5f, 1000.0f)] + public float maxDistance; + + [Tooltip("How far away from the maxDistance to begin fading SSR.")] + [Range(0.0f, 1000.0f)] + public float fadeDistance; + + [Tooltip("Higher = fade out SSRR near the edge of the screen so that reflections don't pop under camera motion.")] + [Range(0.0f, 1.0f)] + public float screenEdgeFading; + + [Tooltip("Enable for better reflections of very bright objects at a performance cost")] + public bool enableHDR; + + // When enabled, we just add our reflections on top of the existing ones. This is physically incorrect, but several + // popular demos and games have taken this approach, and it does hide some artifacts. + [Tooltip("Add reflections on top of existing ones. Not physically correct.")] + public bool additiveReflection; + } + + [Serializable] + public struct ReflectionSettings + { + /// REFLECTIONS + [Tooltip("Max raytracing length.")] + [Range(16, 2048)] + public int maxSteps; + + [Tooltip("Log base 2 of ray tracing coarse step size. Higher traces farther, lower gives better quality silhouettes.")] + [Range(0, 4)] + public int rayStepSize; + + [Tooltip("Typical thickness of columns, walls, furniture, and other objects that reflection rays might pass behind.")] + [Range(0.01f, 10.0f)] + public float widthModifier; + + [Tooltip("Increase if reflections flicker on very rough surfaces.")] + [Range(0.0f, 1.0f)] + public float smoothFallbackThreshold; + + [Tooltip("Start falling back to non-SSR value solution at smoothFallbackThreshold - smoothFallbackDistance, with full fallback occuring at smoothFallbackThreshold.")] + [Range(0.0f, 0.2f)] + public float smoothFallbackDistance; + + [Tooltip("Amplify Fresnel fade out. Increase if floor reflections look good close to the surface and bad farther 'under' the floor.")] + [Range(0.0f, 1.0f)] + public float fresnelFade; + + [Tooltip("Higher values correspond to a faster Fresnel fade as the reflection changes from the grazing angle.")] + [Range(0.1f, 10.0f)] + public float fresnelFadePower; + + [Tooltip("Controls how blurry reflections get as objects are further from the camera. 0 is constant blur no matter trace distance or distance from camera. 1 fully takes into account both factors.")] + [Range(0.0f, 1.0f)] + public float distanceBlur; + } + + [Serializable] + public struct AdvancedSettings + { + /// ADVANCED + [Range(0.0f, 0.99f)] + [Tooltip("Increase to decrease flicker in scenes; decrease to prevent ghosting (especially in dynamic scenes). 0 gives maximum performance.")] + public float temporalFilterStrength; + + [Tooltip("Enable to limit ghosting from applying the temporal filter.")] + public bool useTemporalConfidence; + + [Tooltip("Enable to allow rays to pass behind objects. This can lead to more screen-space reflections, but the reflections are more likely to be wrong.")] + public bool traceBehindObjects; + + [Tooltip("Enable to increase quality of the sharpest reflections (through filtering), at a performance cost.")] + public bool highQualitySharpReflections; + + [Tooltip("Improves quality in scenes with varying smoothness, at a potential performance cost.")] + public bool traceEverywhere; + + [Tooltip("Enable to force more surfaces to use reflection probes if you see streaks on the sides of objects or bad reflections of their backs.")] + public bool treatBackfaceHitAsMiss; + + [Tooltip("Enable for a performance gain in scenes where most glossy objects are horizontal, like floors, water, and tables. Leave on for scenes with glossy vertical objects.")] + public bool allowBackwardsRays; + + [Tooltip("Improve visual fidelity of reflections on rough surfaces near corners in the scene, at the cost of a small amount of performance.")] + public bool improveCorners; + + [Tooltip("Half resolution SSRR is much faster, but less accurate. Quality can be reclaimed for some performance by doing the resolve at full resolution.")] + public SSRResolution resolution; + + [Tooltip("Drastically improves reflection reconstruction quality at the expense of some performance.")] + public bool bilateralUpsample; + + [Tooltip("Improve visual fidelity of mirror reflections at the cost of a small amount of performance.")] + public bool reduceBanding; + + [Tooltip("Enable to limit the effect a few bright pixels can have on rougher surfaces")] + public bool highlightSuppression; + } + + [Serializable] + public struct DebugSettings + { + /// DEBUG + [Tooltip("Various Debug Visualizations")] + public SSRDebugMode debugMode; + } + + + [SerializeField] + public SSRSettings settings = SSRSettings.defaultSettings; + + ///////////// Unexposed Variables ////////////////// + + // Perf optimization we still need to test across platforms + [Tooltip("Enable to try and bypass expensive bilateral upsampling away from edges. There is a slight performance hit for generating the edge buffers, but a potentially high performance savings from bypassing bilateral upsampling where it is unneeded. Test on your target platforms to see if performance improves.")] + private bool useEdgeDetector = false; + + // Debug variable, useful for forcing all surfaces in a scene to reflection with arbitrary sharpness/roughness + [Range(-4.0f, 4.0f)] + private float mipBias = 0.0f; + + // Flag for whether to knock down the reflection term by occlusion stored in the gbuffer. Currently consistently gives + // better results when true, so this flag is private for now. + private bool useOcclusion = true; + + // When enabled, all filtering is performed at the highest resolution. This is extraordinarily slow, and should only be used during development. + private bool fullResolutionFiltering = false; + + // Crude sky fallback, feature-gated until next revision + private bool fallbackToSky = false; + + // For next release; will improve quality at the expense of performance + private bool computeAverageRayDistance = false; + + // Internal values for temporal filtering + private bool m_HasInformationFromPreviousFrame; + private Matrix4x4 m_PreviousWorldToCameraMatrix; + private RenderTexture m_PreviousDepthBuffer; + private RenderTexture m_PreviousHitBuffer; + private RenderTexture m_PreviousReflectionBuffer; + + [NonSerialized] + private RenderTextureUtility m_RTU = new RenderTextureUtility(); + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/ScreenSpaceReflection"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + // Shader pass indices used by the effect + private enum PassIndex + { + RayTraceStep1 = 0, + RayTraceStep2 = 1, + RayTraceStep4 = 2, + RayTraceStep8 = 3, + RayTraceStep16 = 4, + CompositeFinal = 5, + Blur = 6, + CompositeSSR = 7, + Blit = 8, + EdgeGeneration = 9, + MinMipGeneration = 10, + HitPointToReflections = 11, + BilateralKeyPack = 12, + BlitDepthAsCSZ = 13, + TemporalFilter = 14, + AverageRayDistanceGeneration = 15, + PoissonBlur = 16, + } + + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + GetComponent().depthTextureMode |= DepthTextureMode.Depth; + } + + void OnDisable() + { + if (m_Material) + DestroyImmediate(m_Material); + if (m_PreviousDepthBuffer) + DestroyImmediate(m_PreviousDepthBuffer); + if (m_PreviousHitBuffer) + DestroyImmediate(m_PreviousHitBuffer); + if (m_PreviousReflectionBuffer) + DestroyImmediate(m_PreviousReflectionBuffer); + + m_Material = null; + m_PreviousDepthBuffer = null; + m_PreviousHitBuffer = null; + m_PreviousReflectionBuffer = null; + } + + private void PreparePreviousBuffers(int w, int h) + { + if (m_PreviousDepthBuffer != null) + { + if ((m_PreviousDepthBuffer.width != w) || (m_PreviousDepthBuffer.height != h)) + { + DestroyImmediate(m_PreviousDepthBuffer); + DestroyImmediate(m_PreviousHitBuffer); + DestroyImmediate(m_PreviousReflectionBuffer); + m_PreviousDepthBuffer = null; + m_PreviousHitBuffer = null; + m_PreviousReflectionBuffer = null; + } + } + if (m_PreviousDepthBuffer == null) + { + m_PreviousDepthBuffer = new RenderTexture(w, h, 0, RenderTextureFormat.RFloat); + m_PreviousHitBuffer = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf); + m_PreviousReflectionBuffer = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf); + } + } + + [ImageEffectOpaque] + public void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (material == null) + { + Graphics.Blit(source, destination); + return; + } + if (m_HasInformationFromPreviousFrame) + { + m_HasInformationFromPreviousFrame = (m_PreviousDepthBuffer != null) && + (source.width == m_PreviousDepthBuffer.width) && + (source.height == m_PreviousDepthBuffer.height); + } + bool doTemporalFilterThisFrame = m_HasInformationFromPreviousFrame && settings.advancedSettings.temporalFilterStrength > 0.0; + m_HasInformationFromPreviousFrame = false; + + // Not using deferred shading? Just blit source to destination. + if (Camera.current.actualRenderingPath != RenderingPath.DeferredShading) + { + Graphics.Blit(source, destination); + return; + } + + var rtW = source.width; + var rtH = source.height; + + // RGB: Normals, A: Roughness. + // Has the nice benefit of allowing us to control the filtering mode as well. + RenderTexture bilateralKeyTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.ARGB32); + bilateralKeyTexture.filterMode = FilterMode.Point; + Graphics.Blit(source, bilateralKeyTexture, material, (int)PassIndex.BilateralKeyPack); + material.SetTexture("_NormalAndRoughnessTexture", bilateralKeyTexture); + + float sWidth = source.width; + float sHeight = source.height; + + Vector2 sourceToTempUV = new Vector2(sWidth / rtW, sHeight / rtH); + + int downsampleAmount = (settings.advancedSettings.resolution == SSRResolution.FullResolution) ? 1 : 2; + + rtW = rtW / downsampleAmount; + rtH = rtH / downsampleAmount; + + material.SetVector("_SourceToTempUV", new Vector4(sourceToTempUV.x, sourceToTempUV.y, 1.0f / sourceToTempUV.x, 1.0f / sourceToTempUV.y)); + + + Matrix4x4 P = GetComponent().projectionMatrix; + Vector4 projInfo = new Vector4 + ((-2.0f / (sWidth * P[0])), + (-2.0f / (sHeight * P[5])), + ((1.0f - P[2]) / P[0]), + ((1.0f + P[6]) / P[5])); + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float pixelsPerMeterAtOneMeter = sWidth / (-2.0f * (float)(Math.Tan(GetComponent().fieldOfView / 180.0 * Math.PI * 0.5))); + material.SetFloat("_PixelsPerMeterAtOneMeter", pixelsPerMeterAtOneMeter); + + + float sx = sWidth / 2.0f; + float sy = sHeight / 2.0f; + + Matrix4x4 warpToScreenSpaceMatrix = new Matrix4x4(); + warpToScreenSpaceMatrix.SetRow(0, new Vector4(sx, 0.0f, 0.0f, sx)); + warpToScreenSpaceMatrix.SetRow(1, new Vector4(0.0f, sy, 0.0f, sy)); + warpToScreenSpaceMatrix.SetRow(2, new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); + warpToScreenSpaceMatrix.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); + + Matrix4x4 projectToPixelMatrix = warpToScreenSpaceMatrix * P; + + material.SetVector("_ScreenSize", new Vector2(sWidth, sHeight)); + material.SetVector("_ReflectionBufferSize", new Vector2(rtW, rtH)); + Vector2 invScreenSize = new Vector2((float)(1.0 / sWidth), (float)(1.0 / sHeight)); + + Matrix4x4 worldToCameraMatrix = GetComponent().worldToCameraMatrix; + Matrix4x4 cameraToWorldMatrix = GetComponent().worldToCameraMatrix.inverse; + material.SetVector("_InvScreenSize", invScreenSize); + material.SetVector("_ProjInfo", projInfo); // used for unprojection + material.SetMatrix("_ProjectToPixelMatrix", projectToPixelMatrix); + material.SetMatrix("_WorldToCameraMatrix", worldToCameraMatrix); + material.SetMatrix("_CameraToWorldMatrix", cameraToWorldMatrix); + material.SetInt("_EnableRefine", settings.advancedSettings.reduceBanding ? 1 : 0); + material.SetInt("_AdditiveReflection", settings.basicSettings.additiveReflection ? 1 : 0); + material.SetInt("_ImproveCorners", settings.advancedSettings.improveCorners ? 1 : 0); + material.SetFloat("_ScreenEdgeFading", settings.basicSettings.screenEdgeFading); + material.SetFloat("_MipBias", mipBias); + material.SetInt("_UseOcclusion", useOcclusion ? 1 : 0); + material.SetInt("_BilateralUpsampling", settings.advancedSettings.bilateralUpsample ? 1 : 0); + material.SetInt("_FallbackToSky", fallbackToSky ? 1 : 0); + material.SetInt("_TreatBackfaceHitAsMiss", settings.advancedSettings.treatBackfaceHitAsMiss ? 1 : 0); + material.SetInt("_AllowBackwardsRays", settings.advancedSettings.allowBackwardsRays ? 1 : 0); + material.SetInt("_TraceEverywhere", settings.advancedSettings.traceEverywhere ? 1 : 0); + + float z_f = GetComponent().farClipPlane; + float z_n = GetComponent().nearClipPlane; + + Vector3 cameraClipInfo = (float.IsPositiveInfinity(z_f)) ? + new Vector3(z_n, -1.0f, 1.0f) : + new Vector3(z_n * z_f, z_n - z_f, z_f); + + material.SetVector("_CameraClipInfo", cameraClipInfo); + material.SetFloat("_MaxRayTraceDistance", settings.basicSettings.maxDistance); + material.SetFloat("_FadeDistance", settings.basicSettings.fadeDistance); + material.SetFloat("_LayerThickness", settings.reflectionSettings.widthModifier); + + const int maxMip = 5; + RenderTexture[] reflectionBuffers; + RenderTextureFormat intermediateFormat = settings.basicSettings.enableHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; + + reflectionBuffers = new RenderTexture[maxMip]; + for (int i = 0; i < maxMip; ++i) + { + if (fullResolutionFiltering) + reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat); + else + reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i, 0, intermediateFormat); + // We explicitly interpolate during bilateral upsampling. + reflectionBuffers[i].filterMode = settings.advancedSettings.bilateralUpsample ? FilterMode.Point : FilterMode.Bilinear; + } + + material.SetInt("_EnableSSR", 1); + material.SetInt("_DebugMode", (int)settings.debugSettings.debugMode); + + material.SetInt("_TraceBehindObjects", settings.advancedSettings.traceBehindObjects ? 1 : 0); + + material.SetInt("_MaxSteps", settings.reflectionSettings.maxSteps); + + RenderTexture rayHitTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + + // We have 5 passes for different step sizes + int tracePass = Mathf.Clamp(settings.reflectionSettings.rayStepSize, 0, 4); + Graphics.Blit(source, rayHitTexture, material, tracePass); + + material.SetTexture("_HitPointTexture", rayHitTexture); + // Resolve the hitpoints into the mirror reflection buffer + Graphics.Blit(source, reflectionBuffers[0], material, (int)PassIndex.HitPointToReflections); + + material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]); + material.SetInt("_FullResolutionFiltering", fullResolutionFiltering ? 1 : 0); + + material.SetFloat("_MaxRoughness", 1.0f - settings.reflectionSettings.smoothFallbackThreshold); + material.SetFloat("_RoughnessFalloffRange", settings.reflectionSettings.smoothFallbackDistance); + + material.SetFloat("_SSRMultiplier", settings.basicSettings.reflectionMultiplier); + + RenderTexture[] edgeTextures = new RenderTexture[maxMip]; + if (settings.advancedSettings.bilateralUpsample && useEdgeDetector) + { + edgeTextures[0] = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + Graphics.Blit(source, edgeTextures[0], material, (int)PassIndex.EdgeGeneration); + for (int i = 1; i < maxMip; ++i) + { + edgeTextures[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i); + material.SetInt("_LastMip", i - 1); + Graphics.Blit(edgeTextures[i - 1], edgeTextures[i], material, (int)PassIndex.MinMipGeneration); + } + } + + if (settings.advancedSettings.highQualitySharpReflections) + { + RenderTexture filteredReflections = m_RTU.GetTemporaryRenderTexture(reflectionBuffers[0].width, reflectionBuffers[0].height, 0, reflectionBuffers[0].format); + filteredReflections.filterMode = reflectionBuffers[0].filterMode; + reflectionBuffers[0].filterMode = FilterMode.Bilinear; + Graphics.Blit(reflectionBuffers[0], filteredReflections, material, (int)PassIndex.PoissonBlur); + + // Replace the unfiltered buffer with the newly filtered one. + m_RTU.ReleaseTemporaryRenderTexture(reflectionBuffers[0]); + reflectionBuffers[0] = filteredReflections; + material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]); + } + + // Generate the blurred low-resolution buffers + for (int i = 1; i < maxMip; ++i) + { + RenderTexture inputTex = reflectionBuffers[i - 1]; + + RenderTexture hBlur; + if (fullResolutionFiltering) + hBlur = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat); + else + { + int lowMip = i; + hBlur = m_RTU.GetTemporaryRenderTexture(rtW >> lowMip, rtH >> (i - 1), 0, intermediateFormat); + } + for (int j = 0; j < (fullResolutionFiltering ? (i * i) : 1); ++j) + { + // Currently we blur at the resolution of the previous mip level, we could save bandwidth by blurring directly to the lower resolution. + material.SetVector("_Axis", new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); + material.SetFloat("_CurrentMipLevel", i - 1.0f); + + Graphics.Blit(inputTex, hBlur, material, (int)PassIndex.Blur); + + material.SetVector("_Axis", new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); + + inputTex = reflectionBuffers[i]; + Graphics.Blit(hBlur, inputTex, material, (int)PassIndex.Blur); + } + + material.SetTexture("_ReflectionTexture" + i, reflectionBuffers[i]); + + m_RTU.ReleaseTemporaryRenderTexture(hBlur); + } + + + if (settings.advancedSettings.bilateralUpsample && useEdgeDetector) + { + for (int i = 0; i < maxMip; ++i) + material.SetTexture("_EdgeTexture" + i, edgeTextures[i]); + } + material.SetInt("_UseEdgeDetector", useEdgeDetector ? 1 : 0); + + RenderTexture averageRayDistanceBuffer = m_RTU.GetTemporaryRenderTexture(source.width, source.height, 0, RenderTextureFormat.RHalf); + if (computeAverageRayDistance) + { + Graphics.Blit(source, averageRayDistanceBuffer, material, (int)PassIndex.AverageRayDistanceGeneration); + } + material.SetInt("_UseAverageRayDistance", computeAverageRayDistance ? 1 : 0); + material.SetTexture("_AverageRayDistanceBuffer", averageRayDistanceBuffer); + bool resolveDiffersFromTraceRes = (settings.advancedSettings.resolution == SSRResolution.HalfTraceFullResolve); + RenderTexture finalReflectionBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat); + + material.SetFloat("_FresnelFade", settings.reflectionSettings.fresnelFade); + material.SetFloat("_FresnelFadePower", settings.reflectionSettings.fresnelFadePower); + material.SetFloat("_DistanceBlur", settings.reflectionSettings.distanceBlur); + material.SetInt("_HalfResolution", (settings.advancedSettings.resolution != SSRResolution.FullResolution) ? 1 : 0); + material.SetInt("_HighlightSuppression", settings.advancedSettings.highlightSuppression ? 1 : 0); + Graphics.Blit(reflectionBuffers[0], finalReflectionBuffer, material, (int)PassIndex.CompositeSSR); + material.SetTexture("_FinalReflectionTexture", finalReflectionBuffer); + + + RenderTexture temporallyFilteredBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat); + if (doTemporalFilterThisFrame) + { + material.SetInt("_UseTemporalConfidence", settings.advancedSettings.useTemporalConfidence ? 1 : 0); + material.SetFloat("_TemporalAlpha", settings.advancedSettings.temporalFilterStrength); + material.SetMatrix("_CurrentCameraToPreviousCamera", m_PreviousWorldToCameraMatrix * cameraToWorldMatrix); + material.SetTexture("_PreviousReflectionTexture", m_PreviousReflectionBuffer); + material.SetTexture("_PreviousCSZBuffer", m_PreviousDepthBuffer); + Graphics.Blit(source, temporallyFilteredBuffer, material, (int)PassIndex.TemporalFilter); + + material.SetTexture("_FinalReflectionTexture", temporallyFilteredBuffer); + } + + if (settings.advancedSettings.temporalFilterStrength > 0.0) + { + m_PreviousWorldToCameraMatrix = worldToCameraMatrix; + PreparePreviousBuffers(source.width, source.height); + Graphics.Blit(source, m_PreviousDepthBuffer, material, (int)PassIndex.BlitDepthAsCSZ); + Graphics.Blit(rayHitTexture, m_PreviousHitBuffer); + Graphics.Blit(doTemporalFilterThisFrame ? temporallyFilteredBuffer : finalReflectionBuffer, m_PreviousReflectionBuffer); + + m_HasInformationFromPreviousFrame = true; + } + + + Graphics.Blit(source, destination, material, (int)PassIndex.CompositeFinal); + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + } +} diff --git a/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta new file mode 100644 index 0000000..ae1741a --- /dev/null +++ b/Assets/Cinematic Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: da3ff4a1bef2e8d47a1dfb734aa54de1 +timeCreated: 1433488439 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - ssrShader: {fileID: 4800000, guid: 7e2fcc83af19e744787647ec0ac5d42c, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading.meta b/Assets/Cinematic Effects/TonemappingColorGrading.meta new file mode 100644 index 0000000..d912b32 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 33083b2f3c4953846890c256af8cc606 +folderAsset: yes +timeCreated: 1435676891 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta new file mode 100644 index 0000000..4307c22 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a232fdc401b30b549b2ac3a54d76f6cc +folderAsset: yes +timeCreated: 1448359112 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs new file mode 100644 index 0000000..1e4dfec --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs @@ -0,0 +1,736 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + using UnityEditor; + using UnityEditorInternal; + using System.Reflection; + using System.Collections.Generic; + using System.Linq; + + [CanEditMultipleObjects, CustomEditor(typeof(TonemappingColorGrading))] + public class TonemappingColorGradingEditor : Editor + { + #region Property drawers + [CustomPropertyDrawer(typeof(TonemappingColorGrading.ColorWheelGroup))] + private class ColorWheelGroupDrawer : PropertyDrawer + { + int m_RenderSizePerWheel; + int m_NumberOfWheels; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + var wheelAttribute = (TonemappingColorGrading.ColorWheelGroup)attribute; + property.isExpanded = true; + + m_NumberOfWheels = property.CountInProperty() - 1; + if (m_NumberOfWheels == 0) + return 0f; + + m_RenderSizePerWheel = Mathf.FloorToInt((EditorGUIUtility.currentViewWidth) / m_NumberOfWheels) - 30; + m_RenderSizePerWheel = Mathf.Clamp(m_RenderSizePerWheel, wheelAttribute.minSizePerWheel, wheelAttribute.maxSizePerWheel); + m_RenderSizePerWheel = Mathf.FloorToInt(pixelRatio * m_RenderSizePerWheel); + return ColorWheel.GetColorWheelHeight(m_RenderSizePerWheel); + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (m_NumberOfWheels == 0) + return; + + var width = position.width; + Rect newPosition = new Rect(position.x, position.y, width / m_NumberOfWheels, position.height); + + foreach (SerializedProperty prop in property) + { + if (prop.propertyType == SerializedPropertyType.Color) + prop.colorValue = ColorWheel.DoGUI(newPosition, prop.displayName, prop.colorValue, m_RenderSizePerWheel); + + newPosition.x += width / m_NumberOfWheels; + } + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.IndentedGroup))] + private class IndentedGroupDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0f; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + + foreach (SerializedProperty prop in property) + EditorGUILayout.PropertyField(prop); + + EditorGUI.indentLevel--; + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.ChannelMixer))] + private class ChannelMixerDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0f; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // TODO: Hardcoded variable names, rewrite this function + if (property.type != "ChannelMixerSettings") + return; + + SerializedProperty currentChannel = property.FindPropertyRelative("currentChannel"); + int intCurrentChannel = currentChannel.intValue; + + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.PrefixLabel("Channel"); + if (GUILayout.Toggle(intCurrentChannel == 0, "Red", EditorStyles.miniButtonLeft)) intCurrentChannel = 0; + if (GUILayout.Toggle(intCurrentChannel == 1, "Green", EditorStyles.miniButtonMid)) intCurrentChannel = 1; + if (GUILayout.Toggle(intCurrentChannel == 2, "Blue", EditorStyles.miniButtonRight)) intCurrentChannel = 2; + } + EditorGUILayout.EndHorizontal(); + + SerializedProperty serializedChannel = property.FindPropertyRelative("channels").GetArrayElementAtIndex(intCurrentChannel); + currentChannel.intValue = intCurrentChannel; + + Vector3 v = serializedChannel.vector3Value; + v.x = EditorGUILayout.Slider("Red", v.x, -2f, 2f); + v.y = EditorGUILayout.Slider("Green", v.y, -2f, 2f); + v.z = EditorGUILayout.Slider("Blue", v.z, -2f, 2f); + serializedChannel.vector3Value = v; + + EditorGUI.indentLevel--; + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.Curve))] + private class CurveDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + TonemappingColorGrading.Curve attribute = (TonemappingColorGrading.Curve)base.attribute; + + if (property.propertyType != SerializedPropertyType.AnimationCurve) + { + EditorGUI.LabelField(position, label.text, "Use ClampCurve with an AnimationCurve."); + return; + } + + property.animationCurveValue = EditorGUI.CurveField(position, label, property.animationCurveValue, attribute.color, new Rect(0f, 0f, 1f, 1f)); + } + } + #endregion + + #region Styling + private static Styles s_Styles; + private class Styles + { + public GUIStyle thumb2D = "ColorPicker2DThumb"; + public Vector2 thumb2DSize; + + internal Styles() + { + thumb2DSize = new Vector2( + !Mathf.Approximately(thumb2D.fixedWidth, 0f) ? thumb2D.fixedWidth : thumb2D.padding.horizontal, + !Mathf.Approximately(thumb2D.fixedHeight, 0f) ? thumb2D.fixedHeight : thumb2D.padding.vertical + ); + } + } + + public static readonly Color masterCurveColor = new Color(1f, 1f, 1f, 2f); + public static readonly Color redCurveColor = new Color(1f, 0f, 0f, 2f); + public static readonly Color greenCurveColor = new Color(0f, 1f, 0f, 2f); + public static readonly Color blueCurveColor = new Color(0f, 1f, 1f, 2f); + #endregion + + private TonemappingColorGrading concreteTarget + { + get { return target as TonemappingColorGrading; } + } + + private static float pixelRatio + { + get + { + #if !(UNITY_3 || UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3) + return EditorGUIUtility.pixelsPerPoint; + #else + return 1f; + #endif + } + } + + private bool isHistogramSupported + { + get + { + return concreteTarget.histogramComputeShader != null + && ImageEffectHelper.supportsDX11 + && concreteTarget.histogramShader != null + && concreteTarget.histogramShader.isSupported; + } + } + + private enum HistogramMode + { + Red = 0, + Green = 1, + Blue = 2, + Luminance = 3, + RGB, + } + + private HistogramMode m_HistogramMode = HistogramMode.RGB; + private Rect m_HistogramRect; + private Material m_HistogramMaterial; + private ComputeBuffer m_HistogramBuffer; + private RenderTexture m_HistogramTexture; + + // settings group + private Dictionary> m_GroupFields = new Dictionary>(); + + private void PopulateMap(FieldInfo group) + { + var searchPath = group.Name + "."; + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + settingsGroup.Add(property); + } + } + + private void OnEnable() + { + var settingsGroups = typeof(TonemappingColorGrading).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(TonemappingColorGrading.SettingsGroup), false).Any()); + + foreach (var settingGroup in settingsGroups) + PopulateMap(settingGroup); + + concreteTarget.onFrameEndEditorOnly = OnFrameEnd; + } + + private void OnDisable() + { + concreteTarget.onFrameEndEditorOnly = null; + + if (m_HistogramMaterial != null) + DestroyImmediate(m_HistogramMaterial); + + if (m_HistogramTexture != null) + DestroyImmediate(m_HistogramTexture); + + if (m_HistogramBuffer != null) + m_HistogramBuffer.Release(); + } + + private void SetLUTImportSettings(TextureImporter importer) + { + importer.textureType = TextureImporterType.Advanced; + importer.anisoLevel = 0; + importer.mipmapEnabled = false; + importer.linearTexture = true; + importer.textureFormat = TextureImporterFormat.RGB24; + importer.SaveAndReimport(); + } + + private void DrawFields() + { + foreach (var group in m_GroupFields) + { + var enabledField = group.Value.FirstOrDefault(x => x.propertyPath == group.Key.Name + ".enabled"); + var groupProperty = serializedObject.FindProperty(group.Key.Name); + + GUILayout.Space(5); + bool display = EditorGUIHelper.Header(groupProperty, enabledField); + if (!display) + continue; + + GUILayout.BeginHorizontal(); + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + { + GUILayout.Space(3); + foreach (var field in group.Value.Where(x => x.propertyPath != group.Key.Name + ".enabled")) + { + // Special case for the tonemapping curve field + if (group.Key.FieldType == typeof(TonemappingColorGrading.TonemappingSettings) && + field.propertyType == SerializedPropertyType.AnimationCurve && + concreteTarget.tonemapping.tonemapper != TonemappingColorGrading.Tonemapper.Curve) + continue; + + // Special case for the neutral tonemapper + bool neutralParam = field.name.StartsWith("neutral"); + + if (group.Key.FieldType == typeof(TonemappingColorGrading.TonemappingSettings) && + concreteTarget.tonemapping.tonemapper != TonemappingColorGrading.Tonemapper.Neutral && + neutralParam) + continue; + + if (neutralParam) + EditorGUILayout.PropertyField(field, new GUIContent(ObjectNames.NicifyVariableName(field.name.Substring(7)))); + else + EditorGUILayout.PropertyField(field); + } + + // Bake button + if (group.Key.FieldType == typeof(TonemappingColorGrading.ColorGradingSettings)) + { + EditorGUI.BeginDisabledGroup(!enabledField.boolValue); + + if (GUILayout.Button("Export LUT as PNG", EditorStyles.miniButton)) + { + string path = EditorUtility.SaveFilePanelInProject("Export LUT as PNG", "LUT.png", "png", "Please enter a file name to save the LUT texture to"); + + if (!string.IsNullOrEmpty(path)) + { + Texture2D lut = concreteTarget.BakeLUT(); + + if (!concreteTarget.isGammaColorSpace) + { + var pixels = lut.GetPixels(); + + for (int i = 0; i < pixels.Length; i++) + pixels[i] = pixels[i].linear; + + lut.SetPixels(pixels); + lut.Apply(); + } + + byte[] bytes = lut.EncodeToPNG(); + System.IO.File.WriteAllBytes(path, bytes); + DestroyImmediate(lut); + + AssetDatabase.Refresh(); + TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(path); + SetLUTImportSettings(importer); + } + } + + EditorGUI.EndDisabledGroup(); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + if (s_Styles == null) + s_Styles = new Styles(); + + serializedObject.Update(); + + GUILayout.Label("All following effects will use LDR color buffers.", EditorStyles.miniBoldLabel); + + if (concreteTarget.tonemapping.enabled) + { + Camera camera = concreteTarget.GetComponent(); + + if (camera != null && !camera.hdr) + EditorGUILayout.HelpBox("The camera is not HDR enabled. This will likely break the tonemapper.", MessageType.Warning); + else if (!concreteTarget.validRenderTextureFormat) + EditorGUILayout.HelpBox("The input to tonemapper is not in HDR. Make sure that all effects prior to this are executed in HDR.", MessageType.Warning); + } + + if (concreteTarget.lut.enabled && concreteTarget.lut.texture != null) + { + if (!concreteTarget.validUserLutSize) + { + EditorGUILayout.HelpBox("Invalid LUT size. Should be \"height = sqrt(width)\" (e.g. 256x16).", MessageType.Error); + } + else + { + // Checks import settings on the lut, offers to fix them if invalid + TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(concreteTarget.lut.texture)); + bool valid = importer.anisoLevel == 0 + && importer.mipmapEnabled == false + && importer.linearTexture == true + && (importer.textureFormat == TextureImporterFormat.RGB24 || importer.textureFormat == TextureImporterFormat.AutomaticTruecolor); + + if (!valid) + { + EditorGUILayout.HelpBox("Invalid LUT import settings.", MessageType.Warning); + + GUILayout.Space(-32); + EditorGUILayout.BeginHorizontal(); + { + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Fix", GUILayout.Width(60))) + { + SetLUTImportSettings(importer); + AssetDatabase.Refresh(); + } + GUILayout.Space(8); + } + EditorGUILayout.EndHorizontal(); + GUILayout.Space(11); + } + } + } + + DrawFields(); + + serializedObject.ApplyModifiedProperties(); + } + + private static readonly GUIContent k_HistogramTitle = new GUIContent("Histogram"); + public override GUIContent GetPreviewTitle() + { + return k_HistogramTitle; + } + + public override bool HasPreviewGUI() + { + return isHistogramSupported && targets.Length == 1 && concreteTarget != null && concreteTarget.enabled; + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + serializedObject.Update(); + + if (Event.current.type == EventType.Repaint) + { + // If m_HistogramRect isn't set the preview was just opened so refresh the render to get the histogram data + if (m_HistogramRect.width == 0 && m_HistogramRect.height == 0) + InternalEditorUtility.RepaintAllViews(); + + // Sizing + float width = Mathf.Min(512f, r.width); + float height = Mathf.Min(128f, r.height); + m_HistogramRect = new Rect( + Mathf.Floor(r.x + r.width / 2f - width / 2f), + Mathf.Floor(r.y + r.height / 2f - height / 2f), + width, height + ); + + if (m_HistogramTexture != null) + GUI.DrawTexture(m_HistogramRect, m_HistogramTexture); + } + + // Toolbar + GUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + { + concreteTarget.histogramRefreshOnPlay = GUILayout.Toggle(concreteTarget.histogramRefreshOnPlay, new GUIContent("Refresh on Play", "Keep refreshing the histogram in play mode; this may impact performances."), EditorStyles.miniButton); + GUILayout.FlexibleSpace(); + m_HistogramMode = (HistogramMode)EditorGUILayout.EnumPopup(m_HistogramMode); + } + GUILayout.EndHorizontal(); + + serializedObject.ApplyModifiedProperties(); + + if (EditorGUI.EndChangeCheck()) + InternalEditorUtility.RepaintAllViews(); + } + + private void OnFrameEnd(RenderTexture source) + { + if (Application.isPlaying && !concreteTarget.histogramRefreshOnPlay) + return; + + if (Mathf.Approximately(m_HistogramRect.width, 0) || Mathf.Approximately(m_HistogramRect.height, 0) || !isHistogramSupported) + return; + + // No need to process the full frame to get an histogram, resize the input to a max-size of 512 + int rw = Mathf.Min(Mathf.Max(source.width, source.height), 512); + RenderTexture rt = RenderTexture.GetTemporary(rw, rw, 0); + Graphics.Blit(source, rt); + UpdateHistogram(rt, m_HistogramRect, m_HistogramMode); + Repaint(); + RenderTexture.ReleaseTemporary(rt); + RenderTexture.active = null; + } + + private static readonly int[] k_EmptyBuffer = new int[256 << 2]; + void UpdateHistogram(RenderTexture source, Rect rect, HistogramMode mode) + { + if (m_HistogramMaterial == null) + m_HistogramMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(concreteTarget.histogramShader); + + if (m_HistogramBuffer == null) + m_HistogramBuffer = new ComputeBuffer(256, sizeof(uint) << 2); + + m_HistogramBuffer.SetData(k_EmptyBuffer); + + ComputeShader cs = concreteTarget.histogramComputeShader; + + int kernel = cs.FindKernel("KHistogramGather"); + cs.SetBuffer(kernel, "_Histogram", m_HistogramBuffer); + cs.SetTexture(kernel, "_Source", source); + + int[] channels = null; + switch (mode) + { + case HistogramMode.Luminance: + channels = new[] { 0, 0, 0, 1 }; + break; + case HistogramMode.RGB: + channels = new[] { 1, 1, 1, 0 }; + break; + case HistogramMode.Red: + channels = new[] { 1, 0, 0, 0 }; + break; + case HistogramMode.Green: + channels = new[] { 0, 1, 0, 0 }; + break; + case HistogramMode.Blue: + channels = new[] { 0, 0, 1, 0 }; + break; + } + + cs.SetInts("_Channels", channels); + cs.SetInt("_IsLinear", concreteTarget.isGammaColorSpace ? 0 : 1); + cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1); + + kernel = cs.FindKernel("KHistogramScale"); + cs.SetBuffer(kernel, "_Histogram", m_HistogramBuffer); + cs.SetFloat("_Height", rect.height); + cs.Dispatch(kernel, 1, 1, 1); + + if (m_HistogramTexture == null) + { + DestroyImmediate(m_HistogramTexture); + m_HistogramTexture = new RenderTexture((int)rect.width, (int)rect.height, 0, RenderTextureFormat.ARGB32); + m_HistogramTexture.hideFlags = HideFlags.HideAndDontSave; + } + + m_HistogramMaterial.SetBuffer("_Histogram", m_HistogramBuffer); + m_HistogramMaterial.SetVector("_Size", new Vector2(m_HistogramTexture.width, m_HistogramTexture.height)); + m_HistogramMaterial.SetColor("_ColorR", redCurveColor); + m_HistogramMaterial.SetColor("_ColorG", greenCurveColor); + m_HistogramMaterial.SetColor("_ColorB", blueCurveColor); + m_HistogramMaterial.SetColor("_ColorL", masterCurveColor); + m_HistogramMaterial.SetInt("_Channel", (int)mode); + Graphics.Blit(m_HistogramTexture, m_HistogramTexture, m_HistogramMaterial, (mode == HistogramMode.RGB) ? 1 : 0); + } + + public static class ColorWheel + { + // Constants + private const float PI_2 = Mathf.PI / 2f; + private const float PI2 = Mathf.PI * 2f; + + // hue Wheel + private static Texture2D s_WheelTexture; + private static float s_LastDiameter; + private static GUIStyle s_CenteredStyle; + + public static Color DoGUI(Rect area, string title, Color color, float diameter) + { + var labelrect = area; + labelrect.height = EditorGUIUtility.singleLineHeight; + + if (s_CenteredStyle == null) + { + s_CenteredStyle = new GUIStyle(GUI.skin.GetStyle("Label")) + { + alignment = TextAnchor.UpperCenter + }; + } + + GUI.Label(labelrect, title, s_CenteredStyle); + + // Figure out the wheel draw area + var wheelDrawArea = area; + wheelDrawArea.y += EditorGUIUtility.singleLineHeight; + wheelDrawArea.height = diameter; + + if (wheelDrawArea.width > wheelDrawArea.height) + { + wheelDrawArea.x += (wheelDrawArea.width - wheelDrawArea.height) / 2.0f; + wheelDrawArea.width = area.height; + } + + wheelDrawArea.width = wheelDrawArea.height; + + var radius = diameter / 2.0f; + Vector3 hsv; + Color.RGBToHSV(color, out hsv.x, out hsv.y, out hsv.z); + + // Retina/HDPI screens handling + wheelDrawArea.width /= pixelRatio; + wheelDrawArea.height /= pixelRatio; + float scaledRadius = radius / pixelRatio; + + if (Event.current.type == EventType.Repaint) + { + if (!Mathf.Approximately(diameter, s_LastDiameter)) + { + s_LastDiameter = diameter; + UpdateHueWheel((int)diameter); + } + + // Wheel + GUI.DrawTexture(wheelDrawArea, s_WheelTexture); + + // Thumb + Vector2 thumbPos = Vector2.zero; + float theta = hsv.x * PI2; + float len = hsv.y * scaledRadius; + thumbPos.x = Mathf.Cos(theta + PI_2); + thumbPos.y = Mathf.Sin(theta - PI_2); + thumbPos *= len; + Vector2 thumbSize = s_Styles.thumb2DSize; + Color oldColor = GUI.color; + GUI.color = Color.black; + Vector2 thumbSizeH = thumbSize / 2f; + Handles.color = Color.white; + Handles.DrawAAPolyLine(new Vector2(wheelDrawArea.x + scaledRadius + thumbSizeH.x, wheelDrawArea.y + scaledRadius + thumbSizeH.y), new Vector2(wheelDrawArea.x + scaledRadius + thumbPos.x, wheelDrawArea.y + scaledRadius + thumbPos.y)); + s_Styles.thumb2D.Draw(new Rect(wheelDrawArea.x + scaledRadius + thumbPos.x - thumbSizeH.x, wheelDrawArea.y + scaledRadius + thumbPos.y - thumbSizeH.y, thumbSize.x, thumbSize.y), false, false, false, false); + GUI.color = oldColor; + } + hsv = GetInput(wheelDrawArea, hsv, scaledRadius); + + var sliderDrawArea = wheelDrawArea; + sliderDrawArea.y = sliderDrawArea.yMax; + sliderDrawArea.height = EditorGUIUtility.singleLineHeight; + + hsv.y = GUI.HorizontalSlider(sliderDrawArea, hsv.y, 1e-04f, 1f); + color = Color.HSVToRGB(hsv.x, hsv.y, hsv.z); + return color; + } + + private static readonly int k_ThumbHash = "colorWheelThumb".GetHashCode(); + + private static Vector3 GetInput(Rect bounds, Vector3 hsv, float radius) + { + Event e = Event.current; + var id = GUIUtility.GetControlID(k_ThumbHash, FocusType.Passive, bounds); + + Vector2 mousePos = e.mousePosition; + Vector2 relativePos = mousePos - new Vector2(bounds.x, bounds.y); + + if (e.type == EventType.MouseDown && e.button == 0 && GUIUtility.hotControl == 0) + { + if (bounds.Contains(mousePos)) + { + Vector2 center = new Vector2(bounds.x + radius, bounds.y + radius); + float dist = Vector2.Distance(center, mousePos); + + if (dist <= radius) + { + e.Use(); + GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y); + GUIUtility.hotControl = id; + } + } + } + else if (e.type == EventType.MouseDrag && e.button == 0 && GUIUtility.hotControl == id) + { + Vector2 center = new Vector2(bounds.x + radius, bounds.y + radius); + float dist = Vector2.Distance(center, mousePos); + + if (dist <= radius) + { + e.Use(); + GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y); + } + } + else if (e.type == EventType.MouseUp && e.button == 0 && GUIUtility.hotControl == id) + { + e.Use(); + GUIUtility.hotControl = 0; + } + + return hsv; + } + + private static void GetWheelHueSaturation(float x, float y, float radius, out float hue, out float saturation) + { + float dx = (x - radius) / radius; + float dy = (y - radius) / radius; + float d = Mathf.Sqrt(dx * dx + dy * dy); + hue = Mathf.Atan2(dx, -dy); + hue = 1f - ((hue > 0) ? hue : PI2 + hue) / PI2; + saturation = Mathf.Clamp01(d); + } + + private static void UpdateHueWheel(int diameter) + { + CleanTexture(s_WheelTexture); + s_WheelTexture = MakeTexture(diameter); + + var radius = diameter / 2.0f; + + Color[] pixels = s_WheelTexture.GetPixels(); + + for (int y = 0; y < diameter; y++) + { + for (int x = 0; x < diameter; x++) + { + int index = y * diameter + x; + float dx = (x - radius) / radius; + float dy = (y - radius) / radius; + float d = Mathf.Sqrt(dx * dx + dy * dy); + + // Out of the wheel, early exit + if (d >= 1f) + { + pixels[index] = new Color(0f, 0f, 0f, 0f); + continue; + } + + // red (0) on top, counter-clockwise (industry standard) + float saturation = d; + float hue = Mathf.Atan2(dx, dy); + hue = 1f - ((hue > 0) ? hue : PI2 + hue) / PI2; + Color color = Color.HSVToRGB(hue, saturation, 1f); + + // Quick & dirty antialiasing + color.a = (saturation > 0.99) ? (1f - saturation) * 100f : 1f; + + pixels[index] = color; + } + } + + s_WheelTexture.SetPixels(pixels); + s_WheelTexture.Apply(); + } + + private static Texture2D MakeTexture(int dimension) + { + return new Texture2D(dimension, dimension, TextureFormat.ARGB32, false, true) + { + filterMode = FilterMode.Point, + wrapMode = TextureWrapMode.Clamp, + hideFlags = HideFlags.HideAndDontSave, + alphaIsTransparency = true + }; + } + + private static void CleanTexture(Texture2D texture) + { + if (texture != null) + DestroyImmediate(texture); + } + + public static float GetColorWheelHeight(int renderSizePerWheel) + { + // wheel height + title label + alpha slider + return renderSizePerWheel + 2 * EditorGUIUtility.singleLineHeight; + } + } + } +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta new file mode 100644 index 0000000..20e2686 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 64bb64b30a05a0d4b8afe58a356fc8fb +timeCreated: 1441354689 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta new file mode 100644 index 0000000..ca560cb --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 54915b6fdd14fd042add2d153a8b892d +folderAsset: yes +timeCreated: 1454073138 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png new file mode 100644 index 0000000..0e4bda4 Binary files /dev/null and b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png differ diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta new file mode 100644 index 0000000..45ff902 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 36c322ded1667bc4a867aea5e662c51b +timeCreated: 1454073156 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png new file mode 100644 index 0000000..b8724d4 Binary files /dev/null and b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png differ diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta new file mode 100644 index 0000000..af95d9b --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 6ac6980bae76ac241971e97191b6c30c +timeCreated: 1454073159 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta new file mode 100644 index 0000000..8d2bef2 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 710c12a933657234f859808d82c5dd8b +folderAsset: yes +timeCreated: 1453901184 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute new file mode 100644 index 0000000..0e45d61 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute @@ -0,0 +1,85 @@ +#include "UnityCG.cginc" + +RWStructuredBuffer _Histogram; +Texture2D _Source; + +CBUFFER_START (Params) + uint4 _Channels; + uint _IsLinear; + float _Height; +CBUFFER_END + +// Gathering pass +groupshared uint4 gs_histogram[256]; + +#pragma kernel KHistogramGather +[numthreads(32,32,1)] // Needs at least 256 threads per group +void KHistogramGather(uint3 id : SV_DispatchThreadID, uint3 _group_thread_id : SV_GroupThreadID) +{ + const uint thread_id = _group_thread_id.y * 32 + _group_thread_id.x; + + if (thread_id < 256) + gs_histogram[thread_id] = uint4(0, 0, 0, 0); + + uint sw, sh; + _Source.GetDimensions(sw, sh); + + GroupMemoryBarrierWithGroupSync(); + + if (id.x < sw && id.y < sh) + { + // We want a gamma histogram (like Photoshop & all) + float3 color = saturate(_Source[id.xy].xyz); + if (_IsLinear > 0) + color = LinearToGammaSpace(color); + + // Convert color & luminance to histogram bin + uint3 idx_c = (uint3)(round(color * 255.0)); + uint idx_l = (uint)(round(dot(color.rgb, float3(0.2126, 0.7152, 0.0722)) * 255.0)); + + // Fill the group shared histogram + if (_Channels.r > 0) InterlockedAdd(gs_histogram[idx_c.x].x, 1); // Red + if (_Channels.g > 0) InterlockedAdd(gs_histogram[idx_c.y].y, 1); // Green + if (_Channels.b > 0) InterlockedAdd(gs_histogram[idx_c.z].z, 1); // Blue + if (_Channels.a > 0) InterlockedAdd(gs_histogram[idx_l].w, 1); // Luminance + } + + GroupMemoryBarrierWithGroupSync(); + + // Merge + if (thread_id < 256) + { + uint4 h = gs_histogram[thread_id]; + InterlockedAdd(_Histogram[thread_id].x, h.x); // Red + InterlockedAdd(_Histogram[thread_id].y, h.y); // Green + InterlockedAdd(_Histogram[thread_id].z, h.z); // Blue + InterlockedAdd(_Histogram[thread_id].w, h.w); // Luminance + } +} + +// Scaling pass +groupshared uint4 gs_pyramid[256]; + +#pragma kernel KHistogramScale +[numthreads(16,16,1)] +void KHistogramScale(uint3 _group_thread_id : SV_GroupThreadID) +{ + const uint thread_id = _group_thread_id.y * 16 + _group_thread_id.x; + gs_pyramid[thread_id] = _Histogram[thread_id]; + + GroupMemoryBarrierWithGroupSync(); + + // Parallel reduction to find the max value + [unroll] + for(uint i = 256 >> 1; i > 0; i >>= 1) + { + if(thread_id < i) + gs_pyramid[thread_id] = max(gs_pyramid[thread_id], gs_pyramid[thread_id + i]); + + GroupMemoryBarrierWithGroupSync(); + } + + // Actual scaling + float4 factor = _Height / (float4)gs_pyramid[0]; + _Histogram[thread_id] = (uint4)round(_Histogram[thread_id] * factor); +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta new file mode 100644 index 0000000..e276c48 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5ee4b74fa28a3e74e89423dd49705fc5 +timeCreated: 1436170077 +licenseType: Free +ComputeShaderImporter: + currentBuildTarget: 5 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader new file mode 100644 index 0000000..c78673c --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader @@ -0,0 +1,104 @@ +Shader "Hidden/TonemappingColorGradingHistogram" +{ + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 5.0 + #include "UnityCG.cginc" + + struct v_data + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + StructuredBuffer _Histogram; + float2 _Size; + uint _Channel; + float4 _ColorR; + float4 _ColorG; + float4 _ColorB; + float4 _ColorL; + + v_data vert(appdata_img v) + { + v_data o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; + return o; + } + + float4 frag_channel(v_data i) : SV_Target + { + const float4 COLORS[4] = { _ColorR, _ColorG, _ColorB, _ColorL }; + + float remapI = i.uv.x * 255.0; + uint index = floor(remapI); + float delta = frac(remapI); + float v1 = _Histogram[index][_Channel]; + float v2 = _Histogram[min(index + 1, 255)][_Channel]; + float h = v1 * (1.0 - delta) + v2 * delta; + uint y = (uint)round(i.uv.y * _Size.y); + + float4 color = float4(0.0, 0.0, 0.0, 0.0); + float fill = step(y, h); + color = lerp(color, COLORS[_Channel], fill); + return color; + } + + float4 frag_rgb(v_data i) : SV_Target + { + const float4 COLORS[3] = { _ColorR, _ColorG, _ColorB }; + + float4 targetColor = float4(0.0, 0.0, 0.0, 0.0); + float4 emptyColor = float4(0.0, 0.0, 0.0, 0.0); + float fill = 0; + + for (int j = 0; j < 3; j++) + { + float remapI = i.uv.x * 255.0; + uint index = floor(remapI); + float delta = frac(remapI); + float v1 = _Histogram[index][j]; + float v2 = _Histogram[min(index + 1, 255)][j]; + float h = v1 * (1.0 - delta) + v2 * delta; + uint y = (uint)round(i.uv.y * _Size.y); + float fill = step(y, h); + float4 color = lerp(emptyColor, COLORS[j], fill); + targetColor += color; + } + + return saturate(targetColor); + } + + ENDCG + + // (0) Channel + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag_channel + + ENDCG + } + + // (1) RGB + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag_rgb + + ENDCG + } + } + FallBack off +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta new file mode 100644 index 0000000..5d62a23 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9a8e838691462194482a43a02e424876 +timeCreated: 1436173774 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc new file mode 100644 index 0000000..15d952c --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc @@ -0,0 +1,246 @@ +#include "UnityCG.cginc" + +sampler2D _MainTex; +half4 _MainTex_TexelSize; + +half _Exposure; +half _ToneCurveRange; +sampler2D _ToneCurve; +half4 _NeutralTonemapperParams1; +half4 _NeutralTonemapperParams2; + +sampler2D _LutTex; +half4 _LutParams; + +sampler2D _LumTex; +half _AdaptationSpeed; +half _MiddleGrey; +half _AdaptationMin; +half _AdaptationMax; + +inline half LinToPerceptual(half3 color) +{ + half lum = Luminance(color); + return log(max(lum, 0.001)); +} + +inline half PerceptualToLin(half f) +{ + return exp(f); +} + +half4 frag_log(v2f_img i) : SV_Target +{ + half sum = 0.0; + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1,-1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1, 1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1, 1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1,-1)).rgb); + half avg = sum / 4.0; + return half4(avg, avg, avg, avg); +} + +half4 frag_exp(v2f_img i) : SV_Target +{ + half sum = 0.0; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1,-1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1, 1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1,-1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1, 1)).x; + half avg = PerceptualToLin(sum / 4.0); + return half4(avg, avg, avg, saturate(0.0125 * _AdaptationSpeed)); +} + +half3 apply_lut(sampler2D tex, half3 uv, half3 scaleOffset) +{ + uv.z *= scaleOffset.z; + half shift = floor(uv.z); + uv.xy = uv.xy * scaleOffset.z * scaleOffset.xy + 0.5 * scaleOffset.xy; + uv.x += shift * scaleOffset.y; + uv.xyz = lerp(tex2D(tex, uv.xy).rgb, tex2D(tex, uv.xy + half2(scaleOffset.y, 0)).rgb, uv.z - shift); + return uv; +} + +half3 ToCIE(half3 color) +{ + // RGB -> XYZ conversion + // http://www.w3.org/Graphics/Color/sRGB + // The official sRGB to XYZ conversion matrix is (following ITU-R BT.709) + // 0.4125 0.3576 0.1805 + // 0.2126 0.7152 0.0722 + // 0.0193 0.1192 0.9505 + half3x3 RGB2XYZ = { 0.5141364, 0.3238786, 0.16036376, 0.265068, 0.67023428, 0.06409157, 0.0241188, 0.1228178, 0.84442666 }; + half3 XYZ = mul(RGB2XYZ, color.rgb); + + // XYZ -> Yxy conversion + half3 Yxy; + Yxy.r = XYZ.g; + half temp = dot(half3(1.0, 1.0, 1.0), XYZ.rgb); + Yxy.gb = XYZ.rg / temp; + return Yxy; +} + +half3 FromCIE(half3 Yxy) +{ + // Yxy -> XYZ conversion + half3 XYZ; + XYZ.r = Yxy.r * Yxy.g / Yxy.b; + XYZ.g = Yxy.r; + + // Copy luminance Y + XYZ.b = Yxy.r * (1 - Yxy.g - Yxy.b) / Yxy.b; + + // XYZ -> RGB conversion + // The official XYZ to sRGB conversion matrix is (following ITU-R BT.709) + // 3.2410 -1.5374 -0.4986 + // -0.9692 1.8760 0.0416 + // 0.0556 -0.2040 1.0570 + half3x3 XYZ2RGB = { 2.5651, -1.1665, -0.3986, -1.0217, 1.9777, 0.0439, 0.0753, -0.2543, 1.1892 }; + return mul(XYZ2RGB, XYZ); +} + +half3 tonemapACES(half3 color) +{ + color *= _Exposure; + + // See https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ + const half a = 2.51; + const half b = 0.03; + const half c = 2.43; + const half d = 0.59; + const half e = 0.14; + return saturate((color * (a * color + b)) / (color * (c * color + d) + e)); +} + +half3 tonemapPhotographic(half3 color) +{ + color *= _Exposure; + return 1.0 - exp2(-color); +} + +half3 tonemapHable(half3 color) +{ + const half a = 0.15; + const half b = 0.50; + const half c = 0.10; + const half d = 0.20; + const half e = 0.02; + const half f = 0.30; + const half w = 11.2; + + color *= _Exposure * 2.0; + half3 curr = ((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f; + color = w; + half3 whiteScale = 1.0 / (((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f); + return curr * whiteScale; +} + +half3 tonemapHejlDawson(half3 color) +{ + const half a = 6.2; + const half b = 0.5; + const half c = 1.7; + const half d = 0.06; + + color *= _Exposure; + color = max((0.0).xxx, color - (0.004).xxx); + color = (color * (a * color + b)) / (color * (a * color + c) + d); + return color * color; +} + +half3 tonemapReinhard(half3 color) +{ + half lum = Luminance(color); + half lumTm = lum * _Exposure; + half scale = lumTm / (1.0 + lumTm); + return color * scale / lum; +} + +half3 tonemapCurve(half3 color) +{ + color *= _Exposure; + half3 cie = ToCIE(color); + half newLum = tex2D(_ToneCurve, half2(cie.r * _ToneCurveRange, 0.5)).r; + cie.r = newLum; + return FromCIE(cie); +} + +half3 neutralCurve(half3 x, half a, half b, half c, half d, half e, half f) +{ + return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f; +} + +half3 tonemapNeutral(half3 color) +{ + color *= _Exposure; + + // Tonemap + half a = _NeutralTonemapperParams1.x; + half b = _NeutralTonemapperParams1.y; + half c = _NeutralTonemapperParams1.z; + half d = _NeutralTonemapperParams1.w; + half e = _NeutralTonemapperParams2.x; + half f = _NeutralTonemapperParams2.y; + half whiteLevel = _NeutralTonemapperParams2.z; + half whiteClip = _NeutralTonemapperParams2.w; + + half3 whiteScale = (1.0).xxx / neutralCurve(whiteLevel, a, b, c, d, e, f); + color = neutralCurve(color * whiteScale, a, b, c, d, e, f); + color *= whiteScale; + + // Post-curve white point adjustment + color = color / whiteClip.xxx; + + return color; +} + +half4 frag_tcg(v2f_img i) : SV_Target +{ + half4 color = tex2D(_MainTex, i.uv); + +#if GAMMA_COLORSPACE + color.rgb = GammaToLinearSpace(color.rgb); +#endif + +#if ENABLE_EYE_ADAPTATION + // Fast eye adaptation + half avg_luminance = tex2D(_LumTex, i.uv).x; + half linear_exposure = _MiddleGrey / avg_luminance; + color.rgb *= max(_AdaptationMin, min(_AdaptationMax, linear_exposure)); +#endif + +#if defined(TONEMAPPING_ACES) + color.rgb = tonemapACES(color.rgb); +#elif defined(TONEMAPPING_CURVE) + color.rgb = tonemapCurve(color.rgb); +#elif defined(TONEMAPPING_HABLE) + color.rgb = tonemapHable(color.rgb); +#elif defined(TONEMAPPING_HEJL_DAWSON) + color.rgb = tonemapHejlDawson(color.rgb); +#elif defined(TONEMAPPING_PHOTOGRAPHIC) + color.rgb = tonemapPhotographic(color.rgb); +#elif defined(TONEMAPPING_REINHARD) + color.rgb = tonemapReinhard(color.rgb); +#elif defined(TONEMAPPING_NEUTRAL) + color.rgb = tonemapNeutral(color.rgb); +#endif + +#if ENABLE_COLOR_GRADING + // LUT color grading + half3 color_corrected = apply_lut(_LutTex, saturate(color.rgb), _LutParams.xyz); + color.rgb = lerp(color.rgb, color_corrected, _LutParams.w); +#endif + +#if ENABLE_DITHERING + // Interleaved Gradient Noise from http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare (slide 122) + half3 magic = float3(0.06711056, 0.00583715, 52.9829189); + half gradient = frac(magic.z * frac(dot(i.uv / _MainTex_TexelSize, magic.xy))) / 255.0; + color.rgb -= gradient.xxx; +#endif + +#if GAMMA_COLORSPACE + color.rgb = LinearToGammaSpace(color.rgb); +#endif + + return color; +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta new file mode 100644 index 0000000..30c5736 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a7e68b07525bc7f459ff03bf6cba782a +timeCreated: 1453723607 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader new file mode 100644 index 0000000..e25240c --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader @@ -0,0 +1,304 @@ +Shader "Hidden/TonemappingColorGrading" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + + CGINCLUDE + + #pragma vertex vert_img + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 3.0 + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + // Lut generator + Pass + { + CGPROGRAM + + #pragma fragment frag_lut_gen + #include "TonemappingColorGrading.cginc" + + sampler2D _UserLutTex; + half4 _UserLutParams; + + half3 _WhiteBalance; + half3 _Lift; + half3 _Gamma; + half3 _Gain; + half3 _ContrastGainGamma; + half _Vibrance; + half3 _HSV; + half3 _ChannelMixerRed; + half3 _ChannelMixerGreen; + half3 _ChannelMixerBlue; + sampler2D _CurveTex; + half _Contribution; + + static const half3x3 LIN_2_LMS_MAT = { + 3.90405e-1, 5.49941e-1, 8.92632e-3, + 7.08416e-2, 9.63172e-1, 1.35775e-3, + 2.31082e-2, 1.28021e-1, 9.36245e-1 + }; + + static const half3x3 LMS_2_LIN_MAT = { + 2.85847e+0, -1.62879e+0, -2.48910e-2, + -2.10182e-1, 1.15820e+0, 3.24281e-4, + -4.18120e-2, -1.18169e-1, 1.06867e+0 + }; + + half3 rgb_to_hsv(half3 c) + { + half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + half4 p = lerp(half4(c.bg, K.wz), half4(c.gb, K.xy), step(c.b, c.g)); + half4 q = lerp(half4(p.xyw, c.r), half4(c.r, p.yzx), step(p.x, c.r)); + half d = q.x - min(q.w, q.y); + half e = 1.0e-4; + return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); + } + + half3 hsv_to_rgb(half3 c) + { + half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + half3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); + } + + // CG's fmod() is not the same as GLSL's mod() with negative values, we'll use our own + inline half gmod(half x, half y) + { + return x - y * floor(x / y); + } + + half4 frag_lut_gen(v2f_img i) : SV_Target + { + half3 neutral_lut = tex2D(_MainTex, i.uv).rgb; + half3 final_lut = neutral_lut; + + // User lut + contrib + half3 user_luted = apply_lut(_UserLutTex, final_lut, _UserLutParams.xyz); + final_lut = lerp(final_lut, user_luted, _UserLutParams.w); + + // White balance + half3 lms = mul(LIN_2_LMS_MAT, final_lut); + lms *= _WhiteBalance; + final_lut = mul(LMS_2_LIN_MAT, lms); + + // Lift/gamma/gain + final_lut = _Gain * (_Lift * (1.0 - final_lut) + pow(final_lut, _Gamma)); + final_lut = max(final_lut, 0.0); + + // Hue/saturation/value + half3 hsv = rgb_to_hsv(final_lut); + hsv.x = gmod(hsv.x + _HSV.x, 1.0); + hsv.yz *= _HSV.yz; + final_lut = saturate(hsv_to_rgb(hsv)); + + // Vibrance + half sat = max(final_lut.r, max(final_lut.g, final_lut.b)) - min(final_lut.r, min(final_lut.g, final_lut.b)); + final_lut = lerp(Luminance(final_lut).xxx, final_lut, (1.0 + (_Vibrance * (1.0 - (sign(_Vibrance) * sat))))); + + // Contrast + final_lut = saturate((final_lut - 0.5) * _ContrastGainGamma.x + 0.5); + + // Gain + half f = pow(2.0, _ContrastGainGamma.y) * 0.5; + final_lut = (final_lut < 0.5) ? pow(final_lut, _ContrastGainGamma.y) * f : 1.0 - pow(1.0 - final_lut, _ContrastGainGamma.y) * f; + + // Gamma + final_lut = pow(final_lut, _ContrastGainGamma.z); + + // Color mixer + final_lut = half3( + dot(final_lut, _ChannelMixerRed), + dot(final_lut, _ChannelMixerGreen), + dot(final_lut, _ChannelMixerBlue) + ); + + // Curves + half mr = tex2D(_CurveTex, half2(final_lut.r, 0.5)).a; + half mg = tex2D(_CurveTex, half2(final_lut.g, 0.5)).a; + half mb = tex2D(_CurveTex, half2(final_lut.b, 0.5)).a; + final_lut = half3(mr, mg, mb); + half r = tex2D(_CurveTex, half2(final_lut.r, 0.5)).r; + half g = tex2D(_CurveTex, half2(final_lut.g, 0.5)).g; + half b = tex2D(_CurveTex, half2(final_lut.b, 0.5)).b; + final_lut = half3(r, g, b); + + return half4(final_lut, 1.0); + } + + ENDCG + } + + // The three following passes are used to get an average log luminance using a downsample pyramid + Pass + { + CGPROGRAM + #pragma fragment frag_log + #include "TonemappingColorGrading.cginc" + ENDCG + } + + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + + CGPROGRAM + #pragma fragment frag_exp + #include "TonemappingColorGrading.cginc" + ENDCG + } + + Pass + { + Blend Off + + CGPROGRAM + #pragma fragment frag_exp + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping off + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (ACES) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_ACES + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Curve) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_CURVE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hable) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_HABLE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hejl-Dawson) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_HEJL_DAWSON + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Photographic) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_PHOTOGRAPHIC + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Reinhard) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_REINHARD + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Neutral Hejl/Habble) + Pass + { + CGPROGRAM + #pragma multi_compile __ GAMMA_COLORSPACE + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma fragment frag_tcg + #define TONEMAPPING_NEUTRAL + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Eye adaptation debug slider + Pass + { + CGPROGRAM + #pragma fragment frag_debug + #include "TonemappingColorGrading.cginc" + + half4 frag_debug(v2f_img i) : SV_Target + { + half lum = tex2D(_MainTex, i.uv).r; + half grey = i.uv.x; + + int lum_px = floor(256.0 * lum); + int g_px = floor(256.0 * grey); + + half3 color = half3(grey, grey, grey); + color = lerp(color, half3(1.0, 0.0, 0.0), lum_px == g_px); + + return half4(color, 1.0); + } + ENDCG + } + } +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta new file mode 100644 index 0000000..02d46ec --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 964b34bbab7f5e64fa40f37eaccac1ad +timeCreated: 1435513939 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs new file mode 100644 index 0000000..ff50805 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs @@ -0,0 +1,1078 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + using UnityEngine.Events; + using System; + + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Tonemapping and Color Grading")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class TonemappingColorGrading : MonoBehaviour + { + + // EDITOR ONLY call for allowing the editor to update the histogram + public UnityAction onFrameEndEditorOnly; + + [SerializeField] + private ComputeShader m_HistogramComputeShader; + public ComputeShader histogramComputeShader + { + get + { + if (m_HistogramComputeShader == null) + m_HistogramComputeShader = Resources.Load("HistogramCompute"); + + return m_HistogramComputeShader; + } + } + + [SerializeField] + private Shader m_HistogramShader; + public Shader histogramShader + { + get + { + if (m_HistogramShader == null) + m_HistogramShader = Shader.Find("Hidden/TonemappingColorGradingHistogram"); + + return m_HistogramShader; + } + } + + [SerializeField] + public bool histogramRefreshOnPlay = true; + + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + public class IndentedGroup : PropertyAttribute + {} + + public class ChannelMixer : PropertyAttribute + {} + + public class ColorWheelGroup : PropertyAttribute + { + public int minSizePerWheel = 60; + public int maxSizePerWheel = 150; + + public ColorWheelGroup() + {} + + public ColorWheelGroup(int minSizePerWheel, int maxSizePerWheel) + { + this.minSizePerWheel = minSizePerWheel; + this.maxSizePerWheel = maxSizePerWheel; + } + } + + public class Curve : PropertyAttribute + { + public Color color = Color.white; + + public Curve() + {} + + public Curve(float r, float g, float b, float a) // Can't pass a struct in an attribute + { + color = new Color(r, g, b, a); + } + } + #endregion + + #region Settings + [Serializable] + public struct EyeAdaptationSettings + { + public bool enabled; + + [Min(0f), Tooltip("Midpoint Adjustment.")] + public float middleGrey; + + [Tooltip("The lowest possible exposure value; adjust this value to modify the brightest areas of your level.")] + public float min; + + [Tooltip("The highest possible exposure value; adjust this value to modify the darkest areas of your level.")] + public float max; + + [Min(0f), Tooltip("Speed of linear adaptation. Higher is faster.")] + public float speed; + + [Tooltip("Displays a luminosity helper in the GameView.")] + public bool showDebug; + + public static EyeAdaptationSettings defaultSettings + { + get + { + return new EyeAdaptationSettings + { + enabled = false, + showDebug = false, + middleGrey = 0.5f, + min = -3f, + max = 3f, + speed = 1.5f + }; + } + } + } + + public enum Tonemapper + { + ACES, + Curve, + Hable, + HejlDawson, + Photographic, + Reinhard, + Neutral + } + + [Serializable] + public struct TonemappingSettings + { + public bool enabled; + + [Tooltip("Tonemapping technique to use. ACES is the recommended one.")] + public Tonemapper tonemapper; + + [Min(0f), Tooltip("Adjusts the overall exposure of the scene.")] + public float exposure; + + [Tooltip("Custom tonemapping curve.")] + public AnimationCurve curve; + + // Neutral settings + [Range(-0.1f, 0.1f)] + public float neutralBlackIn; + + [Range(1f, 20f)] + public float neutralWhiteIn; + + [Range(-0.09f, 0.1f)] + public float neutralBlackOut; + + [Range(1f, 19f)] + public float neutralWhiteOut; + + [Range(0.1f, 20f)] + public float neutralWhiteLevel; + + [Range(1f, 10f)] + public float neutralWhiteClip; + + public static TonemappingSettings defaultSettings + { + get + { + return new TonemappingSettings + { + enabled = false, + tonemapper = Tonemapper.Neutral, + exposure = 1f, + curve = CurvesSettings.defaultCurve, + neutralBlackIn = 0.02f, + neutralWhiteIn = 10f, + neutralBlackOut = 0f, + neutralWhiteOut = 10f, + neutralWhiteLevel = 5.3f, + neutralWhiteClip = 10f + }; + } + } + } + + [Serializable] + public struct LUTSettings + { + public bool enabled; + + [Tooltip("Custom lookup texture (strip format, e.g. 256x16).")] + public Texture texture; + + [Range(0f, 1f), Tooltip("Blending factor.")] + public float contribution; + + public static LUTSettings defaultSettings + { + get + { + return new LUTSettings + { + enabled = false, + texture = null, + contribution = 1f + }; + } + } + } + + [Serializable] + public struct ColorWheelsSettings + { + [ColorUsage(false)] + public Color shadows; + + [ColorUsage(false)] + public Color midtones; + + [ColorUsage(false)] + public Color highlights; + + public static ColorWheelsSettings defaultSettings + { + get + { + return new ColorWheelsSettings + { + shadows = Color.white, + midtones = Color.white, + highlights = Color.white + }; + } + } + } + + [Serializable] + public struct BasicsSettings + { + [Range(-2f, 2f), Tooltip("Sets the white balance to a custom color temperature.")] + public float temperatureShift; + + [Range(-2f, 2f), Tooltip("Sets the white balance to compensate for a green or magenta tint.")] + public float tint; + + [Space, Range(-0.5f, 0.5f), Tooltip("Shift the hue of all colors.")] + public float hue; + + [Range(0f, 2f), Tooltip("Pushes the intensity of all colors.")] + public float saturation; + + [Range(-1f, 1f), Tooltip("Adjusts the saturation so that clipping is minimized as colors approach full saturation.")] + public float vibrance; + + [Range(0f, 10f), Tooltip("Brightens or darkens all colors.")] + public float value; + + [Space, Range(0f, 2f), Tooltip("Expands or shrinks the overall range of tonal values.")] + public float contrast; + + [Range(0.01f, 5f), Tooltip("Contrast gain curve. Controls the steepness of the curve.")] + public float gain; + + [Range(0.01f, 5f), Tooltip("Applies a pow function to the source.")] + public float gamma; + + public static BasicsSettings defaultSettings + { + get + { + return new BasicsSettings + { + temperatureShift = 0f, + tint = 0f, + contrast = 1f, + hue = 0f, + saturation = 1f, + value = 1f, + vibrance = 0f, + gain = 1f, + gamma = 1f + }; + } + } + } + + [Serializable] + public struct ChannelMixerSettings + { + public int currentChannel; + public Vector3[] channels; + + public static ChannelMixerSettings defaultSettings + { + get + { + return new ChannelMixerSettings + { + currentChannel = 0, + channels = new[] + { + new Vector3(1f, 0f, 0f), + new Vector3(0f, 1f, 0f), + new Vector3(0f, 0f, 1f) + } + }; + } + } + } + + [Serializable] + public struct CurvesSettings + { + [Curve] + public AnimationCurve master; + + [Curve(1f, 0f, 0f, 1f)] + public AnimationCurve red; + + [Curve(0f, 1f, 0f, 1f)] + public AnimationCurve green; + + [Curve(0f, 1f, 1f, 1f)] + public AnimationCurve blue; + + public static CurvesSettings defaultSettings + { + get + { + return new CurvesSettings + { + master = defaultCurve, + red = defaultCurve, + green = defaultCurve, + blue = defaultCurve + }; + } + } + + public static AnimationCurve defaultCurve + { + get { return new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)); } + } + } + + public enum ColorGradingPrecision + { + Normal = 16, + High = 32 + } + + [Serializable] + public struct ColorGradingSettings + { + public bool enabled; + + [Tooltip("Internal LUT precision. \"Normal\" is 256x16, \"High\" is 1024x32. Prefer \"Normal\" on mobile devices.")] + public ColorGradingPrecision precision; + + [Space, ColorWheelGroup] + public ColorWheelsSettings colorWheels; + + [Space, IndentedGroup] + public BasicsSettings basics; + + [Space, ChannelMixer] + public ChannelMixerSettings channelMixer; + + [Space, IndentedGroup] + public CurvesSettings curves; + + [Space, Tooltip("Use dithering to try and minimize color banding in dark areas.")] + public bool useDithering; + + [Tooltip("Displays the generated LUT in the top left corner of the GameView.")] + public bool showDebug; + + public static ColorGradingSettings defaultSettings + { + get + { + return new ColorGradingSettings + { + enabled = false, + useDithering = false, + showDebug = false, + precision = ColorGradingPrecision.Normal, + colorWheels = ColorWheelsSettings.defaultSettings, + basics = BasicsSettings.defaultSettings, + channelMixer = ChannelMixerSettings.defaultSettings, + curves = CurvesSettings.defaultSettings + }; + } + } + + internal void Reset() + { + curves = CurvesSettings.defaultSettings; + } + } + + [SerializeField, SettingsGroup] + private EyeAdaptationSettings m_EyeAdaptation = EyeAdaptationSettings.defaultSettings; + public EyeAdaptationSettings eyeAdaptation + { + get { return m_EyeAdaptation; } + set { m_EyeAdaptation = value; } + } + + [SerializeField, SettingsGroup] + private TonemappingSettings m_Tonemapping = TonemappingSettings.defaultSettings; + public TonemappingSettings tonemapping + { + get { return m_Tonemapping; } + set + { + m_Tonemapping = value; + SetTonemapperDirty(); + } + } + + [SerializeField, SettingsGroup] + private LUTSettings m_Lut = LUTSettings.defaultSettings; + public LUTSettings lut + { + get { return m_Lut; } + set + { + m_Lut = value; + SetDirty(); + } + } + + [SerializeField, SettingsGroup] + private ColorGradingSettings m_ColorGrading = ColorGradingSettings.defaultSettings; + public ColorGradingSettings colorGrading + { + get { return m_ColorGrading; } + set + { + m_ColorGrading = value; + SetDirty(); + } + } + #endregion + + private Texture2D m_IdentityLut; + private RenderTexture m_InternalLut; + private Texture2D m_CurveTexture; + private Texture2D m_TonemapperCurve; + private float m_TonemapperCurveRange; + + private Texture2D identityLut + { + get + { + if (m_IdentityLut == null || m_IdentityLut.height != lutSize) + { + DestroyImmediate(m_IdentityLut); + m_IdentityLut = GenerateIdentityLut(lutSize); + } + + return m_IdentityLut; + } + } + + private RenderTexture internalLutRt + { + get + { + if (m_InternalLut == null || !m_InternalLut.IsCreated() || m_InternalLut.height != lutSize) + { + DestroyImmediate(m_InternalLut); + m_InternalLut = new RenderTexture(lutSize * lutSize, lutSize, 0, RenderTextureFormat.ARGB32) + { + name = "Internal LUT", + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_InternalLut; + } + } + + private Texture2D curveTexture + { + get + { + if (m_CurveTexture == null) + { + m_CurveTexture = new Texture2D(256, 1, TextureFormat.ARGB32, false, true) + { + name = "Curve texture", + wrapMode = TextureWrapMode.Clamp, + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_CurveTexture; + } + } + + private Texture2D tonemapperCurve + { + get + { + if (m_TonemapperCurve == null) + { + TextureFormat format = TextureFormat.RGB24; + if (SystemInfo.SupportsTextureFormat(TextureFormat.RFloat)) + format = TextureFormat.RFloat; + else if (SystemInfo.SupportsTextureFormat(TextureFormat.RHalf)) + format = TextureFormat.RHalf; + + m_TonemapperCurve = new Texture2D(256, 1, format, false, true) + { + name = "Tonemapper curve texture", + wrapMode = TextureWrapMode.Clamp, + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_TonemapperCurve; + } + } + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/TonemappingColorGrading"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + public bool isGammaColorSpace + { + get { return QualitySettings.activeColorSpace == ColorSpace.Gamma; } + } + + public int lutSize + { + get { return (int)colorGrading.precision; } + } + + private enum Pass + { + LutGen, + AdaptationLog, + AdaptationExpBlend, + AdaptationExp, + TonemappingOff, + TonemappingACES, + TonemappingCurve, + TonemappingHable, + TonemappingHejlDawson, + TonemappingPhotographic, + TonemappingReinhard, + TonemappingNeutral, + AdaptationDebug + } + + public bool validRenderTextureFormat { get; private set; } + public bool validUserLutSize { get; private set; } + + private bool m_Dirty = true; + private bool m_TonemapperDirty = true; + + private RenderTexture m_SmallAdaptiveRt; + private RenderTextureFormat m_AdaptiveRtFormat; + + public void SetDirty() + { + m_Dirty = true; + } + + public void SetTonemapperDirty() + { + m_TonemapperDirty = true; + } + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + SetDirty(); + SetTonemapperDirty(); + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + if (m_IdentityLut != null) + DestroyImmediate(m_IdentityLut); + + if (m_InternalLut != null) + DestroyImmediate(internalLutRt); + + if (m_SmallAdaptiveRt != null) + DestroyImmediate(m_SmallAdaptiveRt); + + if (m_CurveTexture != null) + DestroyImmediate(m_CurveTexture); + + if (m_TonemapperCurve != null) + DestroyImmediate(m_TonemapperCurve); + + m_Material = null; + m_IdentityLut = null; + m_InternalLut = null; + m_SmallAdaptiveRt = null; + m_CurveTexture = null; + m_TonemapperCurve = null; + } + + private void OnValidate() + { + SetDirty(); + SetTonemapperDirty(); + } + + private static Texture2D GenerateIdentityLut(int dim) + { + Color[] newC = new Color[dim * dim * dim]; + float oneOverDim = 1f / ((float)dim - 1f); + + for (int i = 0; i < dim; i++) + for (int j = 0; j < dim; j++) + for (int k = 0; k < dim; k++) + newC[i + (j * dim) + (k * dim * dim)] = new Color((float)i * oneOverDim, Mathf.Abs((float)k * oneOverDim), (float)j * oneOverDim, 1f); + + Texture2D tex2D = new Texture2D(dim * dim, dim, TextureFormat.RGB24, false, true) + { + name = "Identity LUT", + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + tex2D.SetPixels(newC); + tex2D.Apply(); + + return tex2D; + } + + // An analytical model of chromaticity of the standard illuminant, by Judd et al. + // http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D + // Slightly modifed to adjust it with the D65 white point (x=0.31271, y=0.32902). + private float StandardIlluminantY(float x) + { + return 2.87f * x - 3f * x * x - 0.27509507f; + } + + // CIE xy chromaticity to CAT02 LMS. + // http://en.wikipedia.org/wiki/LMS_color_space#CAT02 + private Vector3 CIExyToLMS(float x, float y) + { + float Y = 1f; + float X = Y * x / y; + float Z = Y * (1f - x - y) / y; + + float L = 0.7328f * X + 0.4296f * Y - 0.1624f * Z; + float M = -0.7036f * X + 1.6975f * Y + 0.0061f * Z; + float S = 0.0030f * X + 0.0136f * Y + 0.9834f * Z; + + return new Vector3(L, M, S); + } + + private Vector3 GetWhiteBalance() + { + float t1 = colorGrading.basics.temperatureShift; + float t2 = colorGrading.basics.tint; + + // Get the CIE xy chromaticity of the reference white point. + // Note: 0.31271 = x value on the D65 white point + float x = 0.31271f - t1 * (t1 < 0f ? 0.1f : 0.05f); + float y = StandardIlluminantY(x) + t2 * 0.05f; + + // Calculate the coefficients in the LMS space. + Vector3 w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point + Vector3 w2 = CIExyToLMS(x, y); + return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z); + } + + private static Color NormalizeColor(Color c) + { + float sum = (c.r + c.g + c.b) / 3f; + + if (Mathf.Approximately(sum, 0f)) + return new Color(1f, 1f, 1f, 1f); + + return new Color + { + r = c.r / sum, + g = c.g / sum, + b = c.b / sum, + a = 1f + }; + } + + private void GenerateLiftGammaGain(out Color lift, out Color gamma, out Color gain) + { + Color nLift = NormalizeColor(colorGrading.colorWheels.shadows); + Color nGamma = NormalizeColor(colorGrading.colorWheels.midtones); + Color nGain = NormalizeColor(colorGrading.colorWheels.highlights); + + float avgLift = (nLift.r + nLift.g + nLift.b) / 3f; + float avgGamma = (nGamma.r + nGamma.g + nGamma.b) / 3f; + float avgGain = (nGain.r + nGain.g + nGain.b) / 3f; + + // Magic numbers + const float liftScale = 0.1f; + const float gammaScale = 0.5f; + const float gainScale = 0.5f; + + float liftR = (nLift.r - avgLift) * liftScale; + float liftG = (nLift.g - avgLift) * liftScale; + float liftB = (nLift.b - avgLift) * liftScale; + + float gammaR = Mathf.Pow(2f, (nGamma.r - avgGamma) * gammaScale); + float gammaG = Mathf.Pow(2f, (nGamma.g - avgGamma) * gammaScale); + float gammaB = Mathf.Pow(2f, (nGamma.b - avgGamma) * gammaScale); + + float gainR = Mathf.Pow(2f, (nGain.r - avgGain) * gainScale); + float gainG = Mathf.Pow(2f, (nGain.g - avgGain) * gainScale); + float gainB = Mathf.Pow(2f, (nGain.b - avgGain) * gainScale); + + const float minGamma = 0.01f; + float invGammaR = 1f / Mathf.Max(minGamma, gammaR); + float invGammaG = 1f / Mathf.Max(minGamma, gammaG); + float invGammaB = 1f / Mathf.Max(minGamma, gammaB); + + lift = new Color(liftR, liftG, liftB); + gamma = new Color(invGammaR, invGammaG, invGammaB); + gain = new Color(gainR, gainG, gainB); + } + + private void GenCurveTexture() + { + AnimationCurve master = colorGrading.curves.master; + AnimationCurve red = colorGrading.curves.red; + AnimationCurve green = colorGrading.curves.green; + AnimationCurve blue = colorGrading.curves.blue; + + Color[] pixels = new Color[256]; + + for (float i = 0f; i <= 1f; i += 1f / 255f) + { + float m = Mathf.Clamp(master.Evaluate(i), 0f, 1f); + float r = Mathf.Clamp(red.Evaluate(i), 0f, 1f); + float g = Mathf.Clamp(green.Evaluate(i), 0f, 1f); + float b = Mathf.Clamp(blue.Evaluate(i), 0f, 1f); + pixels[(int)Mathf.Floor(i * 255f)] = new Color(r, g, b, m); + } + + curveTexture.SetPixels(pixels); + curveTexture.Apply(); + } + + private bool CheckUserLut() + { + validUserLutSize = (lut.texture.height == (int)Mathf.Sqrt(lut.texture.width)); + return validUserLutSize; + } + + private bool CheckSmallAdaptiveRt() + { + if (m_SmallAdaptiveRt != null) + return false; + + m_AdaptiveRtFormat = RenderTextureFormat.ARGBHalf; + + if (SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGHalf)) + m_AdaptiveRtFormat = RenderTextureFormat.RGHalf; + + m_SmallAdaptiveRt = new RenderTexture(1, 1, 0, m_AdaptiveRtFormat); + m_SmallAdaptiveRt.hideFlags = HideFlags.DontSave; + + return true; + } + + private void OnGUI() + { + if (Event.current.type != EventType.Repaint) + return; + + int yoffset = 0; + + // Color grading debug + if (m_InternalLut != null && colorGrading.enabled && colorGrading.showDebug) + { + Graphics.DrawTexture(new Rect(0f, yoffset, lutSize * lutSize, lutSize), internalLutRt); + yoffset += lutSize; + } + + // Eye Adaptation debug + if (m_SmallAdaptiveRt != null && eyeAdaptation.enabled && eyeAdaptation.showDebug) + { + m_Material.SetPass((int)Pass.AdaptationDebug); + Graphics.DrawTexture(new Rect(0f, yoffset, 256, 16), m_SmallAdaptiveRt, m_Material); + } + } + + [ImageEffectTransformsToLDR] + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { +#if UNITY_EDITOR + validRenderTextureFormat = true; + + if (source.format != RenderTextureFormat.ARGBHalf && source.format != RenderTextureFormat.ARGBFloat) + validRenderTextureFormat = false; +#endif + + if (isGammaColorSpace) + material.EnableKeyword("GAMMA_COLORSPACE"); + else + material.DisableKeyword("GAMMA_COLORSPACE"); + + material.DisableKeyword("ENABLE_EYE_ADAPTATION"); + material.DisableKeyword("ENABLE_COLOR_GRADING"); + material.DisableKeyword("ENABLE_DITHERING"); + + Texture lutUsed = null; + float lutContrib = 1f; + + RenderTexture rtSquared = null; + RenderTexture[] rts = null; + + if (eyeAdaptation.enabled) + { + bool freshlyBrewedSmallRt = CheckSmallAdaptiveRt(); + int srcSize = source.width < source.height ? source.width : source.height; + + // Fast lower or equal power of 2 + int adaptiveSize = srcSize; + adaptiveSize |= (adaptiveSize >> 1); + adaptiveSize |= (adaptiveSize >> 2); + adaptiveSize |= (adaptiveSize >> 4); + adaptiveSize |= (adaptiveSize >> 8); + adaptiveSize |= (adaptiveSize >> 16); + adaptiveSize -= (adaptiveSize >> 1); + + rtSquared = RenderTexture.GetTemporary(adaptiveSize, adaptiveSize, 0, m_AdaptiveRtFormat); + Graphics.Blit(source, rtSquared); + + int downsample = (int)Mathf.Log(rtSquared.width, 2f); + + int div = 2; + rts = new RenderTexture[downsample]; + for (int i = 0; i < downsample; i++) + { + rts[i] = RenderTexture.GetTemporary(rtSquared.width / div, rtSquared.width / div, 0, m_AdaptiveRtFormat); + div <<= 1; + } + + // Downsample pyramid + var lumRt = rts[downsample - 1]; + Graphics.Blit(rtSquared, rts[0], material, (int)Pass.AdaptationLog); + for (int i = 0; i < downsample - 1; i++) + { + Graphics.Blit(rts[i], rts[i + 1]); + lumRt = rts[i + 1]; + } + + // Keeping luminance values between frames, RT restore expected + m_SmallAdaptiveRt.MarkRestoreExpected(); + + material.SetFloat("_AdaptationSpeed", Mathf.Max(eyeAdaptation.speed, 0.001f)); + +#if UNITY_EDITOR + if (Application.isPlaying && !freshlyBrewedSmallRt) + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, (int)Pass.AdaptationExpBlend); + else + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, (int)Pass.AdaptationExp); +#else + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, freshlyBrewedSmallRt ? (int)Pass.AdaptationExp : (int)Pass.AdaptationExpBlend); +#endif + + material.SetFloat("_MiddleGrey", eyeAdaptation.middleGrey); + material.SetFloat("_AdaptationMin", Mathf.Pow(2f, eyeAdaptation.min)); + material.SetFloat("_AdaptationMax", Mathf.Pow(2f, eyeAdaptation.max)); + material.SetTexture("_LumTex", m_SmallAdaptiveRt); + material.EnableKeyword("ENABLE_EYE_ADAPTATION"); + } + + int renderPass = (int)Pass.TonemappingOff; + + if (tonemapping.enabled) + { + if (tonemapping.tonemapper == Tonemapper.Curve) + { + if (m_TonemapperDirty) + { + float range = 1f; + + if (tonemapping.curve.length > 0) + { + range = tonemapping.curve[tonemapping.curve.length - 1].time; + + for (float i = 0f; i <= 1f; i += 1f / 255f) + { + float c = tonemapping.curve.Evaluate(i * range); + tonemapperCurve.SetPixel(Mathf.FloorToInt(i * 255f), 0, new Color(c, c, c)); + } + + tonemapperCurve.Apply(); + } + + m_TonemapperCurveRange = 1f / range; + m_TonemapperDirty = false; + } + + material.SetFloat("_ToneCurveRange", m_TonemapperCurveRange); + material.SetTexture("_ToneCurve", tonemapperCurve); + } + else if (tonemapping.tonemapper == Tonemapper.Neutral) + { + const float scaleFactor = 20f; + const float scaleFactorHalf = scaleFactor * 0.5f; + + float inBlack = tonemapping.neutralBlackIn * scaleFactor + 1f; + float outBlack = tonemapping.neutralBlackOut * scaleFactorHalf + 1f; + float inWhite = tonemapping.neutralWhiteIn / scaleFactor; + float outWhite = 1f - tonemapping.neutralWhiteOut / scaleFactor; + float blackRatio = inBlack / outBlack; + float whiteRatio = inWhite / outWhite; + + const float a = 0.2f; + float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio)); + float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio); + float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio)); + const float e = 0.02f; + const float f = 0.30f; + + material.SetVector("_NeutralTonemapperParams1", new Vector4(a, b, c, d)); + material.SetVector("_NeutralTonemapperParams2", new Vector4(e, f, tonemapping.neutralWhiteLevel, tonemapping.neutralWhiteClip / scaleFactorHalf)); + } + + material.SetFloat("_Exposure", tonemapping.exposure); + renderPass += (int)tonemapping.tonemapper + 1; + } + + if (lut.enabled) + { + Texture tex = lut.texture; + + if (lut.texture == null || !CheckUserLut()) + tex = identityLut; + + lutUsed = tex; + lutContrib = lut.contribution; + material.EnableKeyword("ENABLE_COLOR_GRADING"); + } + + if (colorGrading.enabled) + { + if (m_Dirty || !m_InternalLut.IsCreated()) + { + if (lutUsed == null) + { + material.SetVector("_UserLutParams", new Vector4(1f / identityLut.width, 1f / identityLut.height, identityLut.height - 1f, 1f)); + material.SetTexture("_UserLutTex", identityLut); + } + else + { + material.SetVector("_UserLutParams", new Vector4(1f / lutUsed.width, 1f / lutUsed.height, lutUsed.height - 1f, lut.contribution)); + material.SetTexture("_UserLutTex", lutUsed); + } + + Color lift, gamma, gain; + GenerateLiftGammaGain(out lift, out gamma, out gain); + GenCurveTexture(); + + material.SetVector("_WhiteBalance", GetWhiteBalance()); + material.SetVector("_Lift", lift); + material.SetVector("_Gamma", gamma); + material.SetVector("_Gain", gain); + material.SetVector("_ContrastGainGamma", new Vector3(colorGrading.basics.contrast, colorGrading.basics.gain, 1f / colorGrading.basics.gamma)); + material.SetFloat("_Vibrance", colorGrading.basics.vibrance); + material.SetVector("_HSV", new Vector4(colorGrading.basics.hue, colorGrading.basics.saturation, colorGrading.basics.value)); + material.SetVector("_ChannelMixerRed", colorGrading.channelMixer.channels[0]); + material.SetVector("_ChannelMixerGreen", colorGrading.channelMixer.channels[1]); + material.SetVector("_ChannelMixerBlue", colorGrading.channelMixer.channels[2]); + material.SetTexture("_CurveTex", curveTexture); + internalLutRt.MarkRestoreExpected(); + Graphics.Blit(identityLut, internalLutRt, material, (int)Pass.LutGen); + m_Dirty = false; + } + + lutUsed = internalLutRt; + lutContrib = 1f; + material.EnableKeyword("ENABLE_COLOR_GRADING"); + + if (colorGrading.useDithering) + material.EnableKeyword("ENABLE_DITHERING"); + } + + if (lutUsed != null) + { + material.SetTexture("_LutTex", lutUsed); + material.SetVector("_LutParams", new Vector4(1f / lutUsed.width, 1f / lutUsed.height, lutUsed.height - 1f, lutContrib)); + } + + Graphics.Blit(source, destination, material, renderPass); + + // Cleanup for eye adaptation + if (eyeAdaptation.enabled) + { + for (int i = 0; i < rts.Length; i++) + RenderTexture.ReleaseTemporary(rts[i]); + + RenderTexture.ReleaseTemporary(rtSquared); + } + +#if UNITY_EDITOR + // If we have an on frame end callabck we need to pass a valid result texture + // if destination is null we wrote to the backbuffer so we need to copy that out. + // It's slow and not amazing, but editor only + if (onFrameEndEditorOnly != null) + { + if (destination == null) + { + RenderTexture rt = RenderTexture.GetTemporary(source.width, source.height, 0); + Graphics.Blit(source, rt, material, renderPass); + onFrameEndEditorOnly(rt); + RenderTexture.ReleaseTemporary(rt); + RenderTexture.active = null; + } + else + { + onFrameEndEditorOnly(destination); + } + } +#endif + } + + public Texture2D BakeLUT() + { + Texture2D lut = new Texture2D(internalLutRt.width, internalLutRt.height, TextureFormat.RGB24, false, true); + RenderTexture.active = internalLutRt; + lut.ReadPixels(new Rect(0f, 0f, lut.width, lut.height), 0, 0); + RenderTexture.active = null; + return lut; + } + } +} diff --git a/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta new file mode 100644 index 0000000..ee75f55 --- /dev/null +++ b/Assets/Cinematic Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 58a7625302996c94ba07a8ca3351f668 +timeCreated: 1453901501 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_HistogramComputeShader: {fileID: 7200000, guid: 5ee4b74fa28a3e74e89423dd49705fc5, + type: 3} + - m_HistogramShader: {fileID: 4800000, guid: 9a8e838691462194482a43a02e424876, type: 3} + - m_Shader: {fileID: 4800000, guid: 964b34bbab7f5e64fa40f37eaccac1ad, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickRopes 2/CoreScripts.meta b/Assets/QuickRopes 2/CoreScripts.meta new file mode 100644 index 0000000..833154f --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: da2dd05291975a144870b1d17838eebc +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor.meta b/Assets/QuickRopes 2/CoreScripts/Editor.meta new file mode 100644 index 0000000..87ce869 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 5d08e488c9036014d88374d32b28ec1b +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs new file mode 100644 index 0000000..56d1344 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2Cloth))] +public class QuickRope2ClothEditor : Editor +{ + public const int MAX_CROSS_SEGMENTS = 24; + public const float MIN_RADIUS = 0.001f; + public const float MAX_RADIUS = 500; + + public override void OnInspectorGUI() + { + //QuickRope2Cloth t = (QuickRope2Cloth)target; + + //t.crossSegments = (int)Mathf.Clamp(t.crossSegments, 3, MAX_CROSS_SEGMENTS); + //t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Max Radius", "The maximum radius allowed to be set by the curve."), t.maxRadius), 5, Mathf.Infinity); + //t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve", "The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); + + //if (GUI.changed) + // t.OnInitializeMesh(); + } +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta new file mode 100644 index 0000000..c4da37a --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2ClothEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f079a7158988e7044a8b153dedb299e6 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs new file mode 100644 index 0000000..f386383 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs @@ -0,0 +1,612 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2))] +public class QuickRope2Editor : Editor +{ + QuickRope2 r; + private int currentActiveHandle = -1; + private float guiScale = 0.5f; + private Vector3 prevRopePos = Vector3.zero; + + public const int MAX_CROSS_SEGMENTS = 24; + public const float MIN_RADIUS = 0.001f; + public const float MAX_RADIUS = 500; + + private Vector2 aoScrollPosition = Vector2.zero; + + void OnEnable() + { + r = (QuickRope2)target; + + if (Application.isPlaying) + return; + + CleanupObject(); + r.ApplyRopeSettings(); //r.SetControlPoints(r.ControlPoints); + } + + public override void OnInspectorGUI() + { + r.EDITOR_TAB_SELECTED = GUILayout.Toolbar(r.EDITOR_TAB_SELECTED, new string[] { "Basics", "Physics", "Attach", "Control" }); + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + + bool isCloth = (r.GetComponent() != null); + + switch (r.EDITOR_TAB_SELECTED) + { + case 0: + r.ropeEnd = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Rope End", "The defined end of this rope."), r.ropeEnd, typeof(GameObject), true); + r.jointSpacing = EditorGUILayout.FloatField(new GUIContent("Joint Spacing", "The amount of distance between each joint in the rope object.\n\n Max = " + QuickRope2.MAX_JOINT_SPACING + "\n Min = " + QuickRope2.MIN_JOINT_SPACING + "\n\nTo set a custom the min/max distance, alter the const value in the QuickRopes2.cs script."), r.jointSpacing); + r.showJoints = EditorGUILayout.Toggle(new GUIContent("Preview Joints", "If checked, all joints created will be shown in the Hierarchy. Useful if you are trying to debug custom scripts."), r.showJoints); + QuickRope2.EDITOR_GUI_SCALE = EditorGUILayout.Slider("Editor GUI Scale", QuickRope2.EDITOR_GUI_SCALE, 0.1f, 5f); + guiScale = QuickRope2.EDITOR_GUI_SCALE; + + EditorGUILayout.Separator(); + EditorGUILayout.PrefixLabel("Set Mesh Type"); + EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); int val = GUILayout.Toolbar(-1, new string[] { "None", "Line", "Prefab", "Mesh", "Cloth" }); EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); + switch (val) + { + case 0: + ClearMeshTypes(); + break; + case 1: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + case 2: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + case 3: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + case 4: + ClearMeshTypes(); + r.gameObject.AddComponent(); + break; + } + + + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + EditorGUILayout.PrefixLabel("Mesh Type Settings"); + + if (r.GetComponent() != null) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); EditorGUILayout.LabelField("Use \"Line Renderer\" component below."); EditorGUILayout.EndHorizontal(); + } + + if (r.GetComponent() != null) + { + QuickRope2Prefab t = r.GetComponent(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", t.prefab, typeof(GameObject), false); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.jointScale = EditorGUILayout.FloatField("Scale", t.jointScale); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); r.AlternateJoints = EditorGUILayout.Toggle("Alternate Joints", r.AlternateJoints); EditorGUILayout.EndHorizontal(); + if (r.AlternateJoints) + { + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(35); + r.FirstJointAlternated = EditorGUILayout.Toggle("First Joint Alternated", r.FirstJointAlternated); + EditorGUILayout.EndHorizontal(); + } + } + + if(r.GetComponent()!=null) + { + QuickRope2Mesh t = r.GetComponent(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.meshStatic = EditorGUILayout.Toggle(new GUIContent("Mesh Static", "If checked, the mesh will not automatically update during the \"Update\" method."), t.meshStatic); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.crossSegments = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Sides", "The number of sides in your rope.\n\nMAX: " + MAX_CROSS_SEGMENTS), t.crossSegments), 3, MAX_CROSS_SEGMENTS); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Curve Scale", "The scale of the curve graph below."), t.maxRadius), 1, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve", "The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.textureTiling = EditorGUILayout.FloatField(new GUIContent("Texture Tiling", "Sets the Y value of the texture loaded on this rope."), t.textureTiling); EditorGUILayout.EndHorizontal(); + + } + + if (r.GetComponent() != null) + { + QuickRope2Cloth t = r.GetComponent(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.crossSegments = (int)Mathf.Clamp(t.crossSegments, 3, MAX_CROSS_SEGMENTS); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Max Radius", "The scale of the curve graph below."), t.maxRadius), 1, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve", "The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); EditorGUILayout.EndHorizontal(); + + } + + break; + + case 1: + /* BEGIN PHYSICS REGION */ + #region Physics + + if (r.enablePhysics && isCloth) + r.enablePhysics = false; + + if (isCloth) + { + GUILayout.Label("You cannot use traditional physics\non the Cloth type."); + EditorGUILayout.Separator(); + GUI.enabled = false; + } + + r.enablePhysics = EditorGUILayout.Toggle("Use Physics", r.enablePhysics); + + GUI.enabled = r.enablePhysics; + if (r.EDITOR_SHOW_RIGIDBODY = EditorGUILayout.Foldout(r.EDITOR_SHOW_RIGIDBODY, "Rigidbody Settings")) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.constraint = (RopeConstraint)EditorGUILayout.EnumPopup(new GUIContent("Constraints", ""), r.constraint); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.solverOverride = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Solver Override", ""), r.solverOverride), -1, 255); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.mass = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Mass", ""), r.mass), 0.0001f, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.drag = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Drag", ""), r.drag), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.angDrag = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Angular Drag", ""), r.angDrag), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.useGravity = EditorGUILayout.Toggle(new GUIContent("Use Gravity", ""), r.useGravity); EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.Separator(); + + if (r.EDITOR_SHOW_JOINTSETTINGS = EditorGUILayout.Foldout(r.EDITOR_SHOW_JOINTSETTINGS, "Joint Settings")) + { + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.LowAngXLimit = (r.AngYLimit = r.HighAngXLimit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Swing Limit", ""), r.AngYLimit), 0, 180)) * -1; EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.LTLDamper = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Dampen", ""), r.LTLDamper), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.LTLSpring = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Spring", ""), r.LTLSpring), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.LTLBounce = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Bounce", ""), r.LTLBounce), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.Separator(); + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.AngZLimit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Twist Limit", ""), r.AngZLimit), 0, 180); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.S1LDamper = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Dampen", ""), r.S1LDamper), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.S1LSpring = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Spring", ""), r.S1LSpring), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(40); r.S1LBounce = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Bounce", ""), r.S1LBounce), 0, 500); EditorGUILayout.EndHorizontal(); + EditorGUILayout.Separator(); + + GUI.enabled = ((r.GetComponent() == null) && (r.GetComponent() == null) && (r.GetComponent() == null)); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.breakForce = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Break Force", ""), r.breakForce), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.breakTorque = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Break Torque", ""), r.breakTorque), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + } + EditorGUILayout.Separator(); + + if (r.EDITOR_SHOW_COLLIDERSETTINGS = EditorGUILayout.Foldout(r.EDITOR_SHOW_COLLIDERSETTINGS, "Collider Settings")) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.colliderType = (RopeColliderType)EditorGUILayout.EnumPopup(new GUIContent("Collider Type", ""), r.colliderType); EditorGUILayout.EndHorizontal(); + GUI.enabled = (r.colliderType != RopeColliderType.DEFAULT); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.colliderRadius = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Collider Radius", ""), r.colliderRadius), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.physicsMaterial = (PhysicMaterial)EditorGUILayout.ObjectField(new GUIContent("Physics Material", ""), r.physicsMaterial, typeof(PhysicMaterial), false); EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + } + GUI.enabled = true; + #endregion + + break; + case 2: + if (isCloth) + { + GUILayout.Label("You must attach objects via the \n\"Interactive Cloth\" component below."); + EditorGUILayout.Separator(); + GUI.enabled = false; + } + + if (GUILayout.Button(new GUIContent("Attach GameObject", "Adds a new attachment variable. Assign the variable with the object you would like to attach and the joint index you would like your object to attach to. Attachment is represented by a blue arrow pointing from object to joint index in the scene."))) + { + r.attachedObjects.Add(new RopeAttachedObject()); + } + + EditorGUILayout.Separator(); + + if (r.attachedObjects.Count == 0) + { + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + EditorGUILayout.LabelField("No objects have been attached.\n\nPress \"Attach GameObject\" button above.", GUILayout.Height(55)); + } + + aoScrollPosition = GUILayout.BeginScrollView(aoScrollPosition, GUILayout.MaxHeight(200), GUILayout.MinHeight(200)); + foreach (RopeAttachedObject ao in r.attachedObjects) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(5); ao.go = (GameObject)EditorGUILayout.ObjectField((ao.go==null) ? "Object" : ao.go.name, ao.go, typeof(GameObject), true); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); ao.jointType = (RopeAttachmentJointType)EditorGUILayout.EnumPopup("Con. Type", ao.jointType); EditorGUILayout.EndHorizontal(); + + if (ao.jointType == RopeAttachmentJointType.Hinge) + { + EditorGUILayout.BeginHorizontal(); GUILayout.Space(35); ao.hingeAxis = EditorGUILayout.Vector3Field("Axis", ao.hingeAxis); EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); ao.jointIndex = (int)Mathf.Clamp(EditorGUILayout.IntField("Index", ao.jointIndex), 0, r.Joints.Count-1); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + if (ao.go != null) + { + GUILayout.Space(Screen.width / 3f); if (GUILayout.Button("Center On Index")) { ao.go.transform.position = r.Joints[ao.jointIndex].transform.position; } + } + if (GUILayout.Button("Remove")) { r.attachedObjects.Remove(ao); r.attachedObjects.TrimExcess(); return; } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + GUILayout.EndScrollView(); + GUI.enabled = true; + break; + + case 3: + + if (r.enablePhysics && isCloth) + r.enablePhysics = false; + + if (isCloth) + { + GUILayout.Label("You cannot use the controller\non the Cloth type."); + EditorGUILayout.Separator(); + r.enableRopeController = false; + GUI.enabled = false; + } + + r.enableRopeController = EditorGUILayout.Toggle(new GUIContent("Enable Conroller", ""), r.enableRopeController); + EditorGUILayout.Separator(); + + GUI.enabled = r.enableRopeController; + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.extendRopeKey = (KeyCode)EditorGUILayout.EnumPopup(new GUIContent("Extend Key", ""), r.extendRopeKey); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.retractRopeKey = (KeyCode)EditorGUILayout.EnumPopup(new GUIContent("Retract Key", ""), r.retractRopeKey); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); EditorGUILayout.LabelField("Current Rope Length: " + r.RopeLength); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.maxRopeLength = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Max Length", ""), r.maxRopeLength), r.jointSpacing * 3f, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.minRopeLength = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Min Length", ""), r.minRopeLength), r.jointSpacing * 3f, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.acceleration = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Acceleration", ""), r.acceleration), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.dampening = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Dampening", ""), r.dampening), 0, 1); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.maxVelocity = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Max Velocity", ""), r.maxVelocity), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); GUILayout.Space(25); r.sleepVelocity = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Sleep Velocity", ""), r.sleepVelocity), 0, Mathf.Infinity); EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + + GUI.enabled = true; + break; + } + + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + + if (!Application.isPlaying && GUI.changed) + UpdateRope(); + } + + void CleanupObject() + { + if (r.ropeEnd == null) + return; + + if (!r.enablePhysics) + { + DestroyImmediate(r.ropeEnd.GetComponent()); + DestroyImmediate(r.ropeEnd.GetComponent()); + DestroyImmediate(r.GetComponent()); + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent() == null) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent() == null) + { + //if(r.GetComponent()==null) + // DestroyImmediate(r.GetComponent()); + + DestroyImmediate(r.GetComponent()); + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent() == null) + { + //if (r.GetComponent() == null) + // DestroyImmediate(r.GetComponent()); + + DestroyImmediate(r.GetComponent()); + DestroyImmediate(r.GetComponent()); + } + } + + void ClearMeshTypes() + { + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + } + + bool rebuildAfterCompile = false; + void OnSceneGUI() + { + r = (QuickRope2)target; + if (Application.isPlaying || r.ropeEnd == null) + return; + + if (EditorApplication.isCompiling) + { + rebuildAfterCompile = true; + } + else if (rebuildAfterCompile) + { + rebuildAfterCompile = false; + UpdateRope(); + //return; + } + + Quaternion camLookAt = SceneView.currentDrawingSceneView.camera.transform.rotation; + Vector3 camNormal = SceneView.currentDrawingSceneView.camera.transform.forward; + + + //============== Add Control Point Button ================== + + if (r.ControlPoints.Count == 0 && PlusButton(r.transform.position + (r.ropeEnd.transform.position - r.transform.position) / 2, camLookAt)) + { + r.ControlPoints.Add(r.transform.position + (r.ropeEnd.transform.position - r.transform.position) / 2); + } + + if(r.ControlPoints.Count > 0) + { + // First Add Button + if (PlusButton(r.transform.position + (r.ControlPoints[0] - r.transform.position)/2, camLookAt)) + { + r.ControlPoints.Insert(0, r.transform.position + (r.ControlPoints[0] - r.transform.position) / 2); + currentActiveHandle = 0; + } + + // Last Add Button + if (PlusButton(r.ControlPoints[r.ControlPoints.Count - 1] + (r.ropeEnd.transform.position - r.ControlPoints[r.ControlPoints.Count-1])/2, camLookAt)) + { + r.ControlPoints.Insert(r.ControlPoints.Count, r.ControlPoints[r.ControlPoints.Count - 1] + (r.ropeEnd.transform.position - r.ControlPoints[r.ControlPoints.Count - 1]) / 2); + currentActiveHandle = r.ControlPoints.Count - 1; + } + + for (int i = 0; i < r.ControlPoints.Count - 1; i++) + { + Vector3 btnPos = r.ControlPoints[i] + ((r.ControlPoints[i + 1] - r.ControlPoints[i]) / 2); + + if (PlusButton(btnPos, camLookAt)) + { + r.ControlPoints.Insert(i + 1, btnPos); + currentActiveHandle = i + 1; + } + } + } + + // ================== + if (r.ControlPoints == null) + { + UpdateRope(); + return; + } + + // ================= + for (int i = 0; i < r.ControlPoints.Count; i++) + { + Handles.color = new Color(0, 0, 0, 1); + if (Handles.Button(r.ControlPoints[i], camLookAt, 0.5f * guiScale, 0.5f * guiScale, Handles.CircleCap)) + currentActiveHandle = i; + + if (i == currentActiveHandle) + { + Handles.color = new Color(0.3f, 0.3f, 0.8f); + Handles.DrawSolidDisc(r.ControlPoints[i], camNormal, 0.4f * guiScale); + + Handles.color = Color.white; + r.ControlPoints[i] = Handles.PositionHandle(r.ControlPoints[i], Quaternion.identity); + + if (Event.current.type == EventType.keyDown) + { + if (Event.current.keyCode == KeyCode.P) + { + if (i > 0 && i < r.ControlPoints.Count - 2) + r.ControlPoints.Insert(i + 1, r.ControlPoints[i] + ((r.ControlPoints[i + 1] - r.ControlPoints[i]) / 2)); + //UpdateRope(); + } + + if (Event.current.keyCode == KeyCode.Backspace) + { + r.ControlPoints.RemoveAt(currentActiveHandle); + + currentActiveHandle--; + if (currentActiveHandle == -1 && r.ControlPoints.Count != 0) + currentActiveHandle = 0; + + r.ControlPoints.TrimExcess(); + UpdateRope(); + return; + } + } + } + else + { + Handles.color = new Color(0.2f, 0.2f, 0.4f, 0.8f); + Handles.DrawSolidDisc(r.ControlPoints[i], camNormal, 0.4f * guiScale); + } + } + + //Deal with rope end + { + Handles.color = new Color(0, 0, 0, 1); + if (Handles.Button(r.ropeEnd.transform.position, camLookAt, 0.5f * guiScale, 0.5f * guiScale, Handles.CircleCap)) + currentActiveHandle = 5000; + + if (currentActiveHandle == 5000) + + { + Handles.color = new Color(0.3f, 0.3f, 0.8f); + Handles.DrawSolidDisc(r.ropeEnd.transform.position, camNormal, 0.4f * guiScale); + + Handles.color = Color.white; + r.ropeEnd.transform.position = Handles.PositionHandle(r.ropeEnd.transform.position, Quaternion.identity); + } + else + { + Handles.color = new Color(0.2f, 0.2f, 0.4f, 0.8f); + Handles.DrawSolidDisc(r.ropeEnd.transform.position, camNormal, 0.4f * guiScale); + } + } + + foreach (RopeAttachedObject ao in r.attachedObjects) + { + if (ao.go == null) + continue; + + if (ao.jointIndex > r.Joints.Count - 1) + ao.jointIndex = r.Joints.Count - 1; + + Handles.color = new Color(0.8f, 0.4f, 0f, 0.8f); + Handles.DrawSolidDisc(ao.go.transform.position, camNormal, 0.2f * guiScale); + Handles.DrawSolidDisc(r.Joints[ao.jointIndex].transform.position, camNormal, 0.2f * guiScale); + + float dist = Vector3.Distance(r.Joints[ao.jointIndex].transform.position, ao.go.transform.position); + + if (dist > 0.5f) + Handles.ArrowCap(0, ao.go.transform.position, Quaternion.LookRotation((r.Joints[ao.jointIndex].transform.position - ao.go.transform.position).normalized), dist * 0.8f); + + Handles.color = new Color(0.8f, 0f, 0f, 0.8f); + if (ao.jointType == RopeAttachmentJointType.Hinge && (ao.hingeAxis != Vector3.zero)) + Handles.ArrowCap(0, ao.go.transform.position, ao.go.transform.rotation * Quaternion.LookRotation(ao.hingeAxis), 1); + } + + winRect = GUI.Window(0, winRect, EditWindowFunc, "Edit Selected Control Point"); + + if (GUI.changed) + { + EditorUtility.SetDirty(target); + UpdateRope(); + } + else if (QuickRope2Helper.HasMoved(ref prevRopePos, r.transform.position)) + UpdateRope(); + } + + void UpdateRope() + { + r.jointSpacing = Mathf.Clamp(r.jointSpacing, QuickRope2.MIN_JOINT_SPACING, QuickRope2.MAX_JOINT_SPACING); + if (r.jointSpacing >= QuickRope2.MIN_JOINT_SPACING) + { + r.ApplyRopeSettings(); //r.SetControlPoints(r.ControlPoints); + } + } + + bool PlusButton(Vector3 position, Quaternion direction) + { + Handles.color = new Color(0, 0.8f, 0, 1f); + Handles.DotCap(0, position, direction, 0.2f * guiScale); + return Handles.Button(position, direction, 0.25f * guiScale, 0.25f * guiScale, Handles.RectangleCap); + } + + Vector3 curSelVect = Vector3.zero; + static Rect winRect = new Rect(5, 25, 260, 125); + void EditWindowFunc(int winID) + { + if (currentActiveHandle < 0) + { + GUI.Label(new Rect(45, 55, 260, 125), "Add or select a control point!"); + return; + } + + if (currentActiveHandle == 5000) + curSelVect = r.ropeEnd.transform.position; + else + curSelVect = r.ControlPoints[currentActiveHandle]; + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(30); + EditorGUILayout.LabelField("X: ", GUILayout.Width(50)); + float x = EditorGUILayout.FloatField(curSelVect.x, GUILayout.Width(150)); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(30); + EditorGUILayout.LabelField("Y: ", GUILayout.Width(50)); + float y = EditorGUILayout.FloatField(curSelVect.y, GUILayout.Width(150)); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(30); + EditorGUILayout.LabelField("Z: ", GUILayout.Width(50)); + float z = EditorGUILayout.FloatField(curSelVect.z, GUILayout.Width(150)); + EditorGUILayout.EndHorizontal(); + + if (currentActiveHandle == 5000) + { + r.ropeEnd.transform.position = new Vector3(x, y, z); + GUI.enabled = false; + } + else + { + r.ControlPoints[currentActiveHandle] = new Vector3(x, y, z); + } + + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Average")) + { + if (r.ControlPoints.Count == 1) + { + r.ControlPoints[currentActiveHandle] = (r.ropeEnd.transform.position - r.transform.position) / 2f; + } + else + { + if (currentActiveHandle > 0 && currentActiveHandle < (r.ControlPoints.Count-1)) + { + r.ControlPoints[currentActiveHandle] = (r.ControlPoints[currentActiveHandle - 1] + r.ControlPoints[currentActiveHandle + 1]) / 2f; + } + else if(currentActiveHandle == 0) + { + r.ControlPoints[currentActiveHandle] = (r.transform.position + r.ControlPoints[currentActiveHandle + 1]) / 2f; + } + else if(currentActiveHandle == (r.ControlPoints.Count-1)) + { + r.ControlPoints[currentActiveHandle] = (r.ControlPoints[currentActiveHandle - 1] + r.ropeEnd.transform.position) / 2f; + } + } + + UpdateRope(); + } + if (GUILayout.Button("Zero Vector")) + { + r.ControlPoints[currentActiveHandle] = Vector3.zero; + UpdateRope(); + } + GUILayout.EndHorizontal(); + if (GUILayout.Button("Delete [Backspace]")) + { + r.ControlPoints.RemoveAt(currentActiveHandle); + + currentActiveHandle--; + if (currentActiveHandle == -1 && r.ControlPoints.Count != 0) + currentActiveHandle = 0; + + r.ControlPoints.TrimExcess(); + UpdateRope(); + } + + if (GUI.changed) + UpdateRope(); + + GUI.enabled = true; + GUI.DragWindow(); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta new file mode 100644 index 0000000..55a5725 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Editor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 23701cc23be2f004f92e9acdb9a3ad62 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs new file mode 100644 index 0000000..c81083d --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs @@ -0,0 +1,134 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +public class QuickRope2Menu : MonoBehaviour +{ + [MenuItem("QuickRopes/Ropes/Line Rope")] + static void AddBasicLineRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Line); + r.gameObject.name = "Line_Rope_Start"; + r.ropeEnd.name = "Line_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Ropes/Mesh Rope")] + static void AddBasicMeshRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Mesh); + r.gameObject.name = "Mesh_Rope_Start"; + r.ropeEnd.name = "Mesh_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Ropes/Prefab Rope")] + static void AddBasicPrefabRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Prefab); + r.gameObject.name = "Prefab_Rope_Start"; + r.ropeEnd.name = "Prefab_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Ropes/Cloth Rope")] + static void AddBasicClothRope() + { + QuickRope2 r = QuickRope2.Create(new Vector3(-5, 0, 0), new Vector3(5, 0, 0), BasicRopeTypes.Cloth); + r.gameObject.name = "Cloth_Rope_Start"; + r.ropeEnd.name = "Cloth_Rope_End"; + Selection.activeGameObject = r.gameObject; + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Line Type")] + static void SetLine() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Line Type", true)] + static bool ValidateSetLine() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Mesh Type")] + static void SetMesh() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Mesh Type", true)] + static bool ValidateSetMesh() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Prefab Type")] + static void SetPrefab() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Prefab Type", true)] + static bool ValidateSetPrefab() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/Switch Mesh/Set As Cloth Type")] + static void SetCloth() + { + CleanupObject(); + Selection.activeGameObject.AddComponent(); + } + [MenuItem("QuickRopes/Switch Mesh/Set As Cloth Type", true)] + static bool ValidateSetCloth() + { + return ValidateQR2(); + } + + [MenuItem("QuickRopes/More ->/Video Tutorials")] + static void GotoVids() + { + Application.OpenURL("http://reverieinteractive.com/unity-assets/quickropes/quickropes-video-tutorials"); + } + + [MenuItem("QuickRopes/More ->/Text Tutorials")] + static void GotoAPI() + { + Application.OpenURL("http://reverieinteractive.com/unity-assets/quickropes/quickropes-scripting-examples"); + } + + static void CleanupObject() + { + QuickRope2 r = Selection.activeGameObject.GetComponent(); + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + + if (r.GetComponent()) + { + DestroyImmediate(r.GetComponent()); + } + } + static bool ValidateQR2() + { + if (Selection.activeGameObject == null) + return false; + + return Selection.activeGameObject.GetComponent() != null; + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta new file mode 100644 index 0000000..4529280 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2Menu.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ee660ef9367dc564a8e1095c459109a3 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs new file mode 100644 index 0000000..22ef6ad --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs @@ -0,0 +1,24 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2Mesh))] +public class QuickRope2MeshEditor : Editor +{ + public override void OnInspectorGUI() + { + /* + QuickRope2Mesh t = (QuickRope2Mesh)target; + + t.meshStatic = EditorGUILayout.Toggle(new GUIContent("Mesh Static","If checked, the mesh will not automatically update during the \"Update\" method."), t.meshStatic); + t.crossSegments = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Sides", "The number of sides in your rope.\n\nMAX: " + MAX_CROSS_SEGMENTS), t.crossSegments), 3, MAX_CROSS_SEGMENTS); + t.maxRadius = (int)Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Max Radius","The maximum radius allowed to be set by the curve."), t.maxRadius), 5, Mathf.Infinity); + t.curve = EditorGUILayout.CurveField(new GUIContent("Radius Curve","The ropes radius will be defined by the shape of this curve."), t.curve, Color.white, new Rect(0, 0, 1, t.maxRadius)); + t.textureTiling = EditorGUILayout.FloatField(new GUIContent("Texture Tiling", "Sets the Y value of the texture loaded on this rope."), t.textureTiling); + + if (GUI.changed) + t.OnInitializeMesh(); + + */ + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta new file mode 100644 index 0000000..2fdc206 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2MeshEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2654b7af2fc50fb46b76cdfddeff5ee7 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs new file mode 100644 index 0000000..5213c3e --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs @@ -0,0 +1,25 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor(typeof(QuickRope2Prefab))] +public class QuickRope2PrefabEditor : Editor +{ + public override void OnInspectorGUI() + { + //QuickRope2Prefab t = (QuickRope2Prefab)target; + + //t.prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", t.prefab, typeof(GameObject), false); + //t.jointScale = EditorGUILayout.FloatField("Scale", t.jointScale); + //if (t.alternateJoints = EditorGUILayout.Toggle("Alternate Joints", t.alternateJoints)) + //{ + // EditorGUILayout.BeginHorizontal(); + // GUILayout.Space(25); + // t.firstJointAlternated = EditorGUILayout.Toggle("First Joint Alternated", t.firstJointAlternated); + // EditorGUILayout.EndHorizontal(); + //} + + //if (GUI.changed) + // t.OnInitializeMesh(); + } +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta new file mode 100644 index 0000000..e9ec459 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Editor/QuickRope2PrefabEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 29ce7380d5dcd4a488e9724179ff094d +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs new file mode 100644 index 0000000..8812c9f --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs @@ -0,0 +1,1002 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public enum BasicRopeTypes +{ + NONE, + Line, + Prefab, + Mesh, + Cloth +} + +public enum RopeConstraint +{ + NONE, + X_Y, + Y_Z, + Z_X +} + +public enum RopeColliderType +{ + DEFAULT, + Sphere, + Capsule +} + +public enum RopeAttachmentJointType +{ + Fixed, + Hinge + //Character +} + +[System.Serializable] +public class RopeAttachedObject +{ + public GameObject go; + public RopeAttachmentJointType jointType = RopeAttachmentJointType.Fixed; + public int jointIndex = 0; + public Vector3 hingeAxis = Vector3.forward; + public Joint jointRef = null; +} + + +[System.Serializable] +public class QuickRope2 : MonoBehaviour +{ + #region BASIC ROPE VARIABLES + public const float PRECISION = 0.0001f; + public const int MAX_JOINT_COUNT = 500; + public const float MAX_JOINT_SPACING = 50; + public const float MIN_JOINT_SPACING = 0.1f; + + public GameObject ropeEnd = null; + public LayerMask layer; + public float jointSpacing = 1f; + public bool showJoints = false; + + public event System.Action OnInitializeMesh; + + [HideInInspector()] + [SerializeField] + private GameObject jointPrefab = null; + public GameObject JointPrefab { get { return jointPrefab; } set { jointPrefab = value; } } + + [HideInInspector()] + [SerializeField] + private float jointScale = 1; + public float JointScale { get { return jointScale; } set { jointScale = value; } } + + [HideInInspector()] + [SerializeField] + private bool alternateJoints = false; + public bool AlternateJoints { get { return alternateJoints; } set { alternateJoints = value; } } + + [HideInInspector()] + [SerializeField] + private bool firstJointAlternated = false; + public bool FirstJointAlternated { get { return firstJointAlternated; } set { firstJointAlternated = value; } } + + [HideInInspector()] + [SerializeField] + private List controlPoints = new List(); + public List ControlPoints { get { return controlPoints; } set { controlPoints = value; } } + + [HideInInspector()] + [SerializeField] + private List splinePoints = new List(); + public List SplinePoints { get { return splinePoints; } } + + [HideInInspector()] + [SerializeField] + public List Joints = new List(); + + [HideInInspector()] + [SerializeField] + private List calculatedPositions = new List(); + + [HideInInspector()] + [SerializeField] + private Quaternion[] calculatedRotations; + + [HideInInspector()] + [SerializeField] + public List attachedObjects = new List(); + + public Vector3[] JointPositions + { + get + { + if (Joints.Count == 0) + return new Vector3[] { Vector3.zero }; + + Vector3[] pos = new Vector3[Joints.Count]; + for (int i = 0; i < pos.Length; i++) + { + pos[i] = Joints[i].transform.position; + } + return pos; + } + } + public Quaternion[] JointRotations + { + get + { + Quaternion[] rots = new Quaternion[Joints.Count]; + rots[0] = Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position); + for (int i = 1; i < rots.Length; i++) + { + rots[i] = Quaternion.LookRotation(Joints[i-1].transform.position - Joints[i].transform.position); + } + return rots; + } + } + private int prevJointcount = 0; + private float ropeLength = 0; + public float RopeLength + { + get + { + if (prevJointcount != Joints.Count) + { + ropeLength = 0; + for (int i = 1; i < Joints.Count; i++) + { + ropeLength += Vector3.Distance(Joints[i - 1].transform.position, Joints[i].transform.position); + } + + prevJointcount = Joints.Count; + } + + return ropeLength; + } + } + + private bool freeFallMode = false; + public bool FreeFallMode + { + get { return freeFallMode; } + set + { + freeFallMode = value; + + if (value) + { + Joints[0].GetComponent().connectedBody = null; + Joints[1].transform.parent = Joints[0].transform; + //Joints[1].rigidbody.isKinematic = true; + } + else + { + Joints[0].GetComponent().connectedBody = Joints[1].GetComponent(); + Joints[1].transform.parent = null; + //Joints[1].rigidbody.isKinematic = false; + } + } + } + + private Vector3 pastUp = Vector3.zero; + private Vector3 pRopeEndPos = Vector3.zero; + private bool initialized = false; + #endregion + + #region PHYSICS VARIABLES + public bool enablePhysics = false; + public RopeColliderType colliderType = RopeColliderType.DEFAULT; + public PhysicMaterial physicsMaterial = null; + public float colliderRadius = 0.25f; + + public RopeConstraint constraint = RopeConstraint.NONE; + + public float mass = 1; + public float drag = 0.2f; + public float angDrag = 0.05f; + public bool useGravity = true; + + public float LowAngXLimit = -60; + public float HighAngXLimit = 60; + public float LTLBounce = 0; + public float LTLSpring = 0; + public float LTLDamper = 0; + + public float AngYLimit = 35; + public float AngZLimit = 35; + public float S1LBounce = 0; + public float S1LSpring = 0; + public float S1LDamper = 0; + + public float breakForce = Mathf.Infinity; + public float breakTorque = Mathf.Infinity; + + public int solverOverride = -1; + #endregion + + #region CONTROLLER VARIABLES + private float distBetweenJoints = 0; + private float currentVelocity = 0; + + public bool enableRopeController = false; + public KeyCode extendRopeKey = KeyCode.DownArrow; + public KeyCode retractRopeKey = KeyCode.UpArrow; + public float acceleration = 10; + public float dampening = 0.96f; + public float sleepVelocity = 0.5f; + public float minRopeLength = 5; + public float maxRopeLength = 25; + public float maxVelocity = 5; + #endregion + + [HideInInspector] + public int EDITOR_TAB_SELECTED = 0; + [HideInInspector] + public static float EDITOR_GUI_SCALE = 0.5f; + [HideInInspector] + public bool EDITOR_SHOW_RIGIDBODY = true; + [HideInInspector] + public bool EDITOR_SHOW_JOINTSETTINGS = false; + [HideInInspector] + public bool EDITOR_SHOW_COLLIDERSETTINGS = false; + + void OnDrawGizmosSelected() + { + Gizmos.color = new Color(0.5f, 0.5f, 0.5f, 0.5f); + for (int i = 2; i < splinePoints.Count - 1; i++) + Gizmos.DrawLine(splinePoints[i], splinePoints[i - 1]); + + for (int i = 1; i < controlPoints.Count; i++) + Gizmos.DrawLine(controlPoints[i], controlPoints[i - 1]); + + if (enablePhysics && colliderType != RopeColliderType.DEFAULT) + { + Gizmos.color = new Color(0.1f, 0.7f, 0.4f); + foreach (GameObject go in Joints) + { + Gizmos.DrawWireSphere(go.transform.position, colliderRadius); + } + } + } + void OnDrawGizmos() + { + if (Application.isPlaying) + return; + + if (splinePoints.Count > 3) + { + Gizmos.color = Color.black; + Vector3 prevPt = CalcPositionAtTime(0); + + for (int i = 1; i <= 100; i++) + { + float pm = (float)i / (float)100; + Vector3 currPt = CalcPositionAtTime(pm); + Gizmos.DrawLine(currPt, prevPt); + prevPt = currPt; + } + + Gizmos.color = Color.white; + } + + if (ropeEnd && QuickRope2Helper.HasMoved(ref pRopeEndPos, ropeEnd.transform.position)) + { + ApplyRopeSettings(); + } + } + + void OnDestroy() + { + if (enablePhysics && Application.isPlaying) + { + foreach (RopeAttachedObject ao in attachedObjects) + Destroy(ao.jointRef); + } + + ClearJointObjects(); + } + void Start() + { + if (ropeEnd == null) + return; + + if (!initialized) + { + ApplyRopeSettings(); + AttachObjects(); + } + distBetweenJoints = Vector3.Distance(Joints[0].transform.position, Joints[1].transform.position); + } + void Update() + { + if (!enablePhysics) + return; + + if (freeFallMode) + { + UpdateFreeFall(); + return; + } + + if (!enableRopeController) + return; + + bool applyingForces = false; + if (Input.GetKey(extendRopeKey)) + { + currentVelocity += acceleration * Time.deltaTime; + applyingForces = true; + } + if (Input.GetKey(retractRopeKey)) + { + currentVelocity -= acceleration * Time.deltaTime; + applyingForces = true; + } + + currentVelocity = Mathf.Clamp(currentVelocity, -maxVelocity, maxVelocity); + + if ((RopeLength < minRopeLength && currentVelocity < 0) || (RopeLength > maxRopeLength && currentVelocity > 0)) + { + currentVelocity = 0; + } + + if (currentVelocity > 0) + ExtendRope(currentVelocity); + + if (currentVelocity < 0) + RetractRope(currentVelocity); + + if (!applyingForces) + { + currentVelocity *= dampening; + if (currentVelocity != 0 && Mathf.Abs(currentVelocity) < sleepVelocity) + { + currentVelocity = 0; + //Joints[0].GetComponent().connectedBody = Joints[1].rigidbody; + //Joints[1].transform.parent = null; + //Joints[1].rigidbody.isKinematic = false; + } + } + } + void RetractRope(float velocity) + { + Joints[1].transform.parent = Joints[0].transform; + Joints[0].GetComponent().connectedBody = null; + Joints[1].GetComponent().isKinematic = true; + Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[0].transform.position, Time.deltaTime * velocity * -1); + + if (Vector3.Distance(Joints[1].transform.position, Joints[0].transform.position) <= 0.001f) + { + GameObject go = Joints[1]; + Joints.RemoveAt(1); + Joints.TrimExcess(); + Destroy(go); + //Joints[1].transform.parent = Joints[0].transform; + //Joints[1].rigidbody.isKinematic = true; + } + + Joints[0].GetComponent().connectedBody = Joints[1].GetComponent(); + Joints[1].GetComponent().isKinematic = false; + } + void ExtendRope(float velocity) + { + Joints[0].GetComponent().connectedBody = null; + Joints[1].GetComponent().isKinematic = true; + //Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[1].transform.position + (Joints[1].transform.position - Joints[0].transform.position).normalized, Time.deltaTime * velocity); + Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[1].transform.position - (Joints[0].transform.position - Joints[2].transform.position).normalized , Time.deltaTime * velocity); + + //Debug.DrawRay(Joints[1].transform.position, (Joints[0].transform.position - Joints[1].transform.position).normalized * 10); + //Joints[1].transform.LookAt(Joints[0].transform.position); + + if (Vector3.Distance(Joints[1].transform.position, Joints[0].transform.position) > (distBetweenJoints*1.5f)) + { + GameObject go; + if (JointPrefab != null) + { + go = (GameObject)Instantiate(JointPrefab, Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints), Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position));// Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position)); + float ang = (alternateJoints) ? ((firstJointAlternated) ? ((Joints.Count % 2 == 0) ? 90 : 0) : ((Joints.Count % 2 == 0) ? 0 : 90)) : 0; + go.transform.Rotate(0, 0, ang); + go.transform.localScale = Vector3.one * jointScale; + } + else + { + go = new GameObject("Jnt_" + Joints.Count); + go.transform.position = Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints); + go.transform.rotation = Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position); + float ang = (alternateJoints) ? ((firstJointAlternated) ? ((Joints.Count % 2 == 0) ? 0 : 90) : ((Joints.Count % 2 == 0) ? 90 : 0)) : 0; + go.transform.Rotate(0, 0, ang); + } + + go.layer = gameObject.layer; + go.tag = gameObject.tag; + + if (!showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.GetComponent()) + go.GetComponent().enabled = false; + + AddConfigJoint(go).connectedBody = Joints[1].GetComponent(); + + switch (colliderType) + { + case RopeColliderType.Sphere: + SphereCollider sc; + sc = go.AddComponent(); + sc.radius = colliderRadius; + sc.center = Vector3.zero; + + if (physicsMaterial != null) + sc.sharedMaterial = physicsMaterial; + break; + case RopeColliderType.Capsule: + CapsuleCollider cc; + float len = Vector3.Distance(go.transform.position, Joints[1].transform.position); + + cc = go.AddComponent(); + cc.radius = colliderRadius; + cc.center = new Vector3(0, 0, len / 2f); + cc.direction = 2; + cc.height = len + (cc.radius + cc.radius); + + if (physicsMaterial != null) + cc.sharedMaterial = physicsMaterial; + break; + } + + Joints[1].GetComponent().isKinematic = false; + Joints.Insert(1, go); + Joints.TrimExcess(); + } + + Joints[1].GetComponent().isKinematic = false; + Joints[0].GetComponent().connectedBody = Joints[1].GetComponent(); + } + void UpdateFreeFall() + { + //Joints[1].transform.position = Vector3.MoveTowards(Joints[1].transform.position, Joints[1].transform.position + (Joints[1].transform.position - Joints[0].transform.position).normalized, Time.deltaTime * velocity); + if (RopeLength > maxRopeLength) + { + FreeFallMode = false; + return; + } + + if (Vector3.Distance(Joints[1].transform.position, Joints[0].transform.position) > distBetweenJoints) + { + GameObject go; + if (JointPrefab != null) + { + go = (GameObject)Instantiate(JointPrefab, Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints), Quaternion.identity);// Quaternion.LookRotation(Joints[0].transform.position - Joints[1].transform.position)); + go.transform.LookAt(Joints[0].transform.position); + //go.transform.Rotate(0, 0, Joints[1].transform.eulerAngles.z + 90); + float ang = (alternateJoints) ? ((firstJointAlternated) ? ((Joints.Count % 2 == 0) ? 90 : 0) : ((Joints.Count % 2 == 0) ? 0 : 90)) : 0; + go.transform.Rotate(0, 0, ang); + go.transform.localScale = Vector3.one * jointScale; + } + else + { + go = new GameObject("Jnt_NULL"); + go.transform.position = Joints[1].transform.position - ((Joints[1].transform.position - Joints[0].transform.position).normalized * distBetweenJoints); + go.transform.rotation = Quaternion.identity; + } + + go.layer = gameObject.layer; + go.tag = gameObject.tag; + + if (!showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.GetComponent()) + go.GetComponent().enabled = false; + + AddConfigJoint(go).connectedBody = Joints[1].GetComponent(); + Joints[1].transform.parent = null; + //Joints[1].rigidbody.isKinematic = false; + Joints.Insert(1, go); + Joints.TrimExcess(); + Joints[1].transform.parent = Joints[0].transform; + //Joints[1].rigidbody.isKinematic = true; + } + } + + public void GenerateJointObjects() + { + ClearJointObjects(); + + Joints.Add(gameObject); + + for (int i = 1; i < SplinePoints.Count - 1; i++) + { + GameObject go; + if (JointPrefab != null) + { + go = (GameObject)Instantiate(JointPrefab, SplinePoints[i], calculatedRotations[i]); + + if (alternateJoints) + { + int comparitor = (firstJointAlternated) ? 1 : 0; + go.transform.Rotate(0, 0, (i % 2 == comparitor) ? 90 : 0); + } + + go.transform.localScale = jointPrefab.transform.localScale * jointScale; + } + else + { + go = new GameObject("Jnt_" + i.ToString()); + go.transform.position = SplinePoints[i]; + go.transform.rotation = calculatedRotations[i]; + } + + go.layer = gameObject.layer; + go.tag = gameObject.tag; + + if (!Application.isPlaying) + go.transform.parent = transform; + + if (!showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.GetComponent()) + go.GetComponent().enabled = false; + + Joints.Add(go); + } + + Joints.Add(ropeEnd); + } + public void ClearJointObjects() + { + for(int i = 0; i < Joints.Count; i++) + { + if (Joints[i].GetInstanceID() == gameObject.GetInstanceID() || Joints[i].GetInstanceID() == ropeEnd.GetInstanceID()) + continue; + + if (Application.isPlaying) + { + Destroy(Joints[i]); + } + else + { + DestroyImmediate(Joints[i]); + } + } + + Joints.Clear(); + Joints.TrimExcess(); + } + private void PreCalculateRotations() + { + calculatedRotations = new Quaternion[SplinePoints.Count]; + calculatedRotations[0] = Quaternion.LookRotation(SplinePoints[0] - SplinePoints[1]); + for (int i = 1; i < calculatedRotations.Length; i++) + { + calculatedRotations[i] = Quaternion.LookRotation(SplinePoints[i - 1] - SplinePoints[i]); + } + } + public Quaternion[] GetRotations(Vector3[] points) + { + Vector3[] directions = new Vector3[points.Length]; ; + Quaternion[] rotations = new Quaternion[points.Length]; ; + Vector3 forward, up; + + for (int p = 0; p < points.Length - 1; p++) + directions[p] = points[p + 1] - points[p]; + + directions[points.Length - 1] = directions[points.Length - 2]; + + if (pastUp == Vector3.zero) + { + up = directions[0].x == 0 && directions[0].z == 0 ? Vector3.right : Vector3.up; + } + else + { + up = pastUp; + } + + for (int p = 0; p < points.Length; p++) + { + if (p != 0 && p != points.Length - 1) + { + forward = directions[p] + directions[p - 1]; + } + else + { + if (points[0] == points[points.Length - 1]) forward = directions[points.Length - 1] + directions[0]; + else forward = directions[p]; + } + + if (forward == Vector3.zero) + { + rotations[p] = Quaternion.identity; + continue; + } + + forward.Normalize(); + Vector3 right = Vector3.Cross(up, forward); + if (right == Vector3.zero) + right = Vector3.Cross(new Vector3(-0.3f, 0.1f, 0), new Vector3(0, 0, 0.4f)); + + up = Vector3.Cross(forward, right); + + if (p == 0) + pastUp = up; + + if (right != Vector3.zero) + rotations[p].SetLookRotation(-right, up); + } + + return rotations; + } + private Vector3 CalcPositionAtTime(float t) + { + int numSections = calculatedPositions.Count - 3; + int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1); + float u = t * (float)numSections - (float)currPt; + + Vector3 a = calculatedPositions[currPt]; + Vector3 b = calculatedPositions[currPt + 1]; + Vector3 c = calculatedPositions[currPt + 2]; + Vector3 d = calculatedPositions[currPt + 3]; + + return .5f * ( + (-a + 3f * b - 3f * c + d) * (u * u * u) + + (2f * a - 5f * b + 4f * c - d) * (u * u) + + (-a + c) * u + + 2f * b + ); + } + + #region PHYSICS - Settings + void UpdatePhysics() + { + if (Joints.Count == 0 || !enablePhysics) + return; + + // ====== ADD RIGIDBODIES ========= + for (int r = 0; r < Joints.Count; r++) + { + GameObject go = Joints[r]; + + if (go == null) + return; + + if (go.GetComponent() == null) + go.AddComponent(); + + switch (constraint) + { + case RopeConstraint.NONE: + go.GetComponent().constraints = RigidbodyConstraints.None; + break; + case RopeConstraint.X_Y: + go.GetComponent().constraints = RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezePositionZ; + break; + case RopeConstraint.Y_Z: + go.GetComponent().constraints = RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezePositionX; + break; + case RopeConstraint.Z_X: + go.GetComponent().constraints = RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezePositionY; + break; + } + + if (solverOverride != -1 && solverOverride > 1) + go.GetComponent().solverIterationCount = solverOverride; + + go.GetComponent().mass = mass; + go.GetComponent().angularDrag = angDrag; + go.GetComponent().drag = drag; + go.GetComponent().useGravity = useGravity; + } + + if (Application.isPlaying) + { + // ========= ADD CONFIG JOINTS ============ + for (int c = 0; c < Joints.Count - 1; c++) + AddConfigJoint(Joints[c]).connectedBody = Joints[c + 1].GetComponent(); + + // ========= ADD COLLIDERS ============== + if (colliderType != RopeColliderType.DEFAULT) + AddColliders(); + } + } + ConfigurableJoint AddConfigJoint(GameObject joint) + { + if (Application.isPlaying) + Destroy(joint.GetComponent()); + else + DestroyImmediate(joint.GetComponent()); + + if (Application.isPlaying && joint.GetComponent() && colliderType == RopeColliderType.DEFAULT) + joint.GetComponent().enabled = true; + + ConfigurableJoint cj = joint.AddComponent(); + + cj.anchor = Vector3.zero; + cj.xMotion = ConfigurableJointMotion.Locked; + cj.yMotion = ConfigurableJointMotion.Locked; + cj.zMotion = ConfigurableJointMotion.Locked; + + cj.angularXMotion = ConfigurableJointMotion.Limited; + cj.angularYMotion = ConfigurableJointMotion.Limited; + cj.angularZMotion = ConfigurableJointMotion.Limited; + + cj.lowAngularXLimit = new SoftJointLimit() { limit = LowAngXLimit, bounciness = LTLBounce/*, spring = LTLSpring, damper = LTLDamper*/ }; + cj.highAngularXLimit = new SoftJointLimit() { limit = HighAngXLimit, bounciness = LTLBounce/*, spring = LTLSpring, damper = LTLDamper*/ }; + cj.angularYLimit = new SoftJointLimit() { limit = AngYLimit, bounciness = S1LBounce/*, spring = S1LSpring, damper = S1LDamper*/ }; + cj.angularZLimit = new SoftJointLimit() { limit = AngZLimit, bounciness = S1LBounce/*, spring = S1LSpring, damper = S1LDamper*/ }; + + + if (!enableRopeController) + { + cj.breakForce = breakForce; + cj.breakTorque = breakTorque; + } + + return cj; + } + void AddColliders() + { + if (!Application.isPlaying) + return; + + switch (colliderType) + { + case RopeColliderType.Sphere: + SphereCollider sc; + for (int i = 1; i < Joints.Count - 1; i++) + { + sc = Joints[i].AddComponent(); + sc.radius = colliderRadius; + sc.center = Vector3.zero; + + if (physicsMaterial != null) + sc.sharedMaterial = physicsMaterial; + } + break; + case RopeColliderType.Capsule: + CapsuleCollider cc; + for (int i = 1; i < Joints.Count; i++) + { + float len = Vector3.Distance(Joints[i].transform.position, Joints[i - 1].transform.position); + + if (len < colliderRadius) + continue; + + cc = Joints[i].AddComponent(); + cc.radius = colliderRadius; + cc.center = new Vector3(0, 0, len / 2f); + cc.direction = 2; + cc.height = len + (cc.radius + cc.radius); + + if (physicsMaterial != null) + cc.sharedMaterial = physicsMaterial; + } + break; + } + } + #endregion + + void AttachObjects() + { + if (enablePhysics && Application.isPlaying) + { + foreach (RopeAttachedObject ao in attachedObjects) + { + if (ao.go == null) + continue; + + if (ao.jointIndex > Joints.Count - 1) + ao.jointIndex = Joints.Count - 1; + + switch (ao.jointType) + { + case RopeAttachmentJointType.Fixed: + ao.jointRef = Joints[ao.jointIndex].AddComponent(); + ao.jointRef.connectedBody = ao.go.GetComponent(); + break; + case RopeAttachmentJointType.Hinge: + ao.jointRef = ao.go.AddComponent();//ao.jointRef = Joints[ao.jointIndex].AddComponent(); + (ao.jointRef as HingeJoint).axis = ao.hingeAxis; + ao.jointRef.connectedBody = Joints[ao.jointIndex].GetComponent();//ao.jointRef.connectedBody = ao.go.GetComponent(); + break; + } + } + } + } + + public void ApplyRopeSettings() + { + if (ropeEnd == null) + return; + + // ============== Setup For Spline Point Generation + calculatedPositions.Clear(); calculatedPositions.TrimExcess(); + calculatedPositions.Add(transform.position); + calculatedPositions.AddRange(controlPoints); + calculatedPositions.Add(ropeEnd.transform.position); + calculatedPositions.Insert(0, transform.position - (calculatedPositions[1] - calculatedPositions[0]).normalized); + calculatedPositions.Add(calculatedPositions[calculatedPositions.Count - 1] + (calculatedPositions[calculatedPositions.Count - 1] - calculatedPositions[calculatedPositions.Count - 2]).normalized); + // ================================================ + + float time = 0f; + Vector3 nsPosOffset = Vector3.zero; + + splinePoints.Clear(); splinePoints.TrimExcess(); + splinePoints.Add(CalcPositionAtTime(time)); + + while (time <= 1f) + { + Vector3 p = CalcPositionAtTime(time); + if (Vector3.Distance(splinePoints[splinePoints.Count - 1], (p + nsPosOffset)) >= jointSpacing) + splinePoints.Add(p); + + time += PRECISION; + } + + splinePoints.Add(CalcPositionAtTime(1)); + + PreCalculateRotations(); + + transform.rotation = calculatedRotations[0]; + ropeEnd.transform.rotation = calculatedRotations[calculatedRotations.Length - 1]; + + if (gameObject.GetComponent() == null && gameObject.GetComponent() == null) + GenerateJointObjects(); + + JointPrefab = null; + if (OnInitializeMesh != null) + OnInitializeMesh(); + + if (gameObject.GetComponent() == null) + UpdatePhysics(); + + initialized = true; + } + public void RebuildMesh() + { + if (!initialized) + return; + + if (OnInitializeMesh != null) + OnInitializeMesh(); + } + + public void AttachObject(GameObject obj, int jointIndex, RopeAttachmentJointType jointType, Vector3 hingeAxis, bool centerOnIndex) + { + if (gameObject.GetComponent()) + { + Debug.LogError("You must use the \"Cloth\" component to attach objects when using the Cloth mesh type."); + return; + } + + RopeAttachedObject rao = new RopeAttachedObject(); + rao.go = obj; + rao.jointIndex = jointIndex; + rao.jointType = jointType; + rao.hingeAxis = hingeAxis; + + if (centerOnIndex) + rao.go.transform.position = Joints[rao.jointIndex].transform.position; + + attachedObjects.Add(rao); + + if (Application.isPlaying) + { + if (rao.go == null) + return; + + switch (rao.jointType) + { + case RopeAttachmentJointType.Fixed: + rao.jointRef = Joints[rao.jointIndex].AddComponent(); + rao.jointRef.connectedBody = rao.go.GetComponent(); + break; + case RopeAttachmentJointType.Hinge: + //rao.jointRef = Joints[rao.jointIndex].AddComponent(); + //(rao.jointRef as HingeJoint).axis = rao.hingeAxis; + //rao.jointRef.connectedBody = rao.go.GetComponent(); + + rao.jointRef = rao.go.AddComponent();//ao.jointRef = Joints[ao.jointIndex].AddComponent(); + (rao.jointRef as HingeJoint).axis = rao.hingeAxis; + rao.jointRef.connectedBody = Joints[rao.jointIndex].GetComponent();//ao.jointRef.connectedBody = ao.go.GetComponent(); + + break; + } + } + } + public void AttachObject(GameObject obj, int jointIndex, RopeAttachmentJointType jointType, bool centerOnIndex) + { + AttachObject(obj, jointIndex, jointType, Vector3.forward, centerOnIndex); + } + public void AttachObject(GameObject obj, int jointIndex, bool centerOnIndex) + { + AttachObject(obj, jointIndex, RopeAttachmentJointType.Fixed, centerOnIndex); + } + public void DetachObject(GameObject obj) + { + foreach (RopeAttachedObject ao in attachedObjects) + { + if (ao.go.GetInstanceID() == obj.GetInstanceID()) + { + if (Application.isPlaying) + Destroy(ao.jointRef); + else + DestroyImmediate(ao.jointRef); + + attachedObjects.Remove(ao); + attachedObjects.TrimExcess(); + return; + } + } + } + + public static QuickRope2 Create(GameObject pointA, GameObject pointB, List curvePoints, BasicRopeTypes ropeType) + { + QuickRope2 qr = pointA.AddComponent(); + qr.ropeEnd = pointB; + + switch (ropeType) + { + case BasicRopeTypes.NONE: + break; + case BasicRopeTypes.Line: + qr.gameObject.AddComponent(); + break; + case BasicRopeTypes.Prefab: + qr.gameObject.AddComponent(); + break; + case BasicRopeTypes.Mesh: + qr.gameObject.AddComponent(); + break; + case BasicRopeTypes.Cloth: + qr.gameObject.AddComponent(); + break; + } + + qr.ApplyRopeSettings(); + + return qr; + } + public static QuickRope2 Create(Vector3 pointA, Vector3 pointB, List curvePoints, BasicRopeTypes ropeType) + { + GameObject ob1 = new GameObject("Rope"); + GameObject ob2 = new GameObject("Rope_End"); + + ob1.transform.position = pointA; + ob2.transform.position = pointB; + + return Create(ob1, ob2, curvePoints, ropeType); + } + public static QuickRope2 Create(GameObject pointA, Vector3 pointB, List curvePoints, BasicRopeTypes ropeType) + { + GameObject ob1 = new GameObject("Rope_End"); + + ob1.transform.position = pointB; + + return Create(pointA, ob1, curvePoints, ropeType); + } + public static QuickRope2 Create(Vector3 pointA, GameObject pointB, List curvePoints, BasicRopeTypes ropeType) + { + GameObject ob1 = new GameObject("Rope"); + + ob1.transform.position = pointA; + + return Create(ob1, pointB, curvePoints, ropeType); + } + public static QuickRope2 Create(GameObject pointA, GameObject pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } + public static QuickRope2 Create(Vector3 pointA, GameObject pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } + public static QuickRope2 Create(GameObject pointA, Vector3 pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } + public static QuickRope2 Create(Vector3 pointA, Vector3 pointB, BasicRopeTypes ropeType) + { + return Create(pointA, pointB, null, ropeType); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta new file mode 100644 index 0000000..63c2652 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ae2e5f8c61e368e4aacf8d5b7e443c87 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs new file mode 100644 index 0000000..f54a5cd --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs @@ -0,0 +1,77 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Cloth : MonoBehaviour +{ + public int maxRadius = 5; + public AnimationCurve curve = new AnimationCurve(new Keyframe(0, .3f), new Keyframe(1, .3f)); + public int crossSegments = 6; + + [SerializeField] + private RopeTubeRenderer tube; + private QuickRope2 rope; + private Cloth mFilter; + private SkinnedMeshRenderer mRender; + + void OnEnable() + { + rope = GetComponent(); + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + rope.GenerateJointObjects(); + + if (tube == null) + tube = new RopeTubeRenderer(gameObject, true); + + mRender = gameObject.GetComponent(); + if (mRender == null) + mRender = gameObject.AddComponent(); + + mFilter = gameObject.GetComponent(); + if (mFilter == null) + mFilter = gameObject.AddComponent(); + + GenerateMesh(); + + //if (useAutoTextureTiling) + // gameObject.GetComponent().sharedMaterial.mainTextureScale = new Vector2(rope.Joints.Count / 2f, 1); + + if (gameObject.GetComponent().sharedMaterial == null) + gameObject.GetComponent().sharedMaterial = (Material)Resources.Load("Materials/Rope", typeof(Material)); + } + + public void GenerateMesh() + { + tube.SetPointsAndRotations(rope.JointPositions, rope.GetRotations(rope.JointPositions)); + tube.SetEdgeCount(crossSegments); + + float[] rads = new float[rope.JointPositions.Length]; + for (int i = 0; i < rads.Length; i++) + { + rads[i] = curve.Evaluate(i * (1f / rads.Length)); + } + tube.SetRadiuses(rads); + + tube.Update(); + mRender.sharedMesh = tube.mesh; + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta new file mode 100644 index 0000000..91d9497 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Cloth.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 805db666378c9a9438cabc9bb32ce116 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs new file mode 100644 index 0000000..9516edc --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public class QuickRope2Helper +{ + public static bool HasMoved(ref Vector3 prevPoint, Vector3 curPoint) + { + bool r = Vector3.Distance(curPoint, prevPoint) >= 0.01f; + + if (r) prevPoint = curPoint; + + return r; + } +} + +[System.Serializable] +public class QuickRopeSpline +{ + public List Points; + + public Vector3 Interpolate(float t) + { + if (Points.Count < 4) + return Vector3.zero; + + int numSections = Points.Count - 3; + int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1); + float u = t * (float)numSections - (float)currPt; + + Vector3 a = Points[currPt]; + Vector3 b = Points[currPt + 1]; + Vector3 c = Points[currPt + 2]; + Vector3 d = Points[currPt + 3]; + + return .5f * ( + (-a + 3f * b - 3f * c + d) * (u * u * u) + + (2f * a - 5f * b + 4f * c - d) * (u * u) + + (-a + c) * u + + 2f * b + ); + } + + public void DrawGizmo(float t, int precision, Color splineColor) + { + if (Points.Count < 3) + return; + + Gizmos.color = splineColor; + Vector3 prevPt = Interpolate(0); + + for (int i = 1; i <= 100; i++) + { + float pm = (float)i / (float)100; + Vector3 currPt = Interpolate(pm); + Gizmos.DrawLine(currPt, prevPt); + prevPt = currPt; + } + + Gizmos.color = Color.white; + } +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta new file mode 100644 index 0000000..92a0068 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Helper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cbd90374c07cc4e46b3a75a1c140345b +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs new file mode 100644 index 0000000..0427be0 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs @@ -0,0 +1,70 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[System.Serializable] +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Line : MonoBehaviour +{ + private QuickRope2 rope; + private LineRenderer line; + public bool useAutoTextureTiling = true; + + void OnEnable() + { + rope = GetComponent(); + + if (gameObject.GetComponent() == null) + line = gameObject.AddComponent(); + else + line = gameObject.GetComponent(); + + if (line.sharedMaterial == null) + line.sharedMaterial = (Material)Resources.Load("Materials/RopeLineMaterial", typeof(Material)); + + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + if (rope == null) + return; + + rope.GenerateJointObjects(); + Update(); + + if (useAutoTextureTiling) + gameObject.GetComponent().sharedMaterial.mainTextureScale = new Vector2(rope.Joints.Count / 2f, 1); + } + + void Update() + { + if (line == null) + return; + + if (useAutoTextureTiling && Application.isPlaying) + line.material.mainTextureScale = new Vector2(rope.Joints.Count / 2f, 1); + + int index = 0; + line.SetVertexCount(rope.Joints.Count); + foreach (GameObject go in rope.Joints) + line.SetPosition(index++, go.transform.position); + + //line.SetPosition(index++, rope.ropeEnd.transform.position); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta new file mode 100644 index 0000000..b204fdd --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Line.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7f6c025d5d759cd44b0b01bda0cfbeae +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs new file mode 100644 index 0000000..887987e --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs @@ -0,0 +1,92 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[System.Serializable] +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Mesh : MonoBehaviour +{ + public bool meshStatic = false; + public int maxRadius = 5; + public float textureTiling = 1; + [SerializeField] + public AnimationCurve curve = new AnimationCurve(new Keyframe(0, .3f), new Keyframe(1, .3f)); + public Color[] grad; + public int crossSegments = 6; + + [SerializeField] + public RopeTubeRenderer tube; + [SerializeField] + private QuickRope2 rope; + [SerializeField] + private MeshFilter mFilter; + + void OnEnable() + { + rope = GetComponent(); + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + //rope.GenerateJointObjects(); + + if (tube == null) + tube = new RopeTubeRenderer(gameObject, false); + + tube.calculateTangents = true; + + UpdateMesh(); + } + + public void UpdateMesh() + { + tube.SetPointsAndRotations(rope.JointPositions, rope.GetRotations(rope.JointPositions)); + tube.SetEdgeCount(crossSegments); + + float[] rads = new float[rope.JointPositions.Length]; + for (int i = 0; i < rads.Length; i++) + { + rads[i] = curve.Evaluate(i * (1f / rads.Length)); + } + + tube.SetRadiuses(rads); + tube.Update(); + + gameObject.GetComponent().sharedMaterial.mainTextureScale = new Vector2(rope.Joints.Count * + textureTiling, 1); + } + + void Update() + { + if (meshStatic || !Application.isPlaying) + return; + + float[] rads = new float[rope.JointPositions.Length]; + for (int i = 0; i < rads.Length; i++) + { + rads[i] = curve.Evaluate(i * (1f / rads.Length)); + } + + tube.SetPointsAndRotations(rope.JointPositions, rope.GetRotations(rope.JointPositions)); + tube.SetRadiuses(rads); + tube.Update(); + + gameObject.GetComponent().material.mainTextureScale = new Vector2(rope.Joints.Count * textureTiling, 1); + } +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta new file mode 100644 index 0000000..9d00f3b --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Mesh.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9f1764ce3e0882c47a398e50a6122e3c +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs new file mode 100644 index 0000000..0dc870a --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs @@ -0,0 +1,73 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[RequireComponent(typeof(QuickRope2))] +[ExecuteInEditMode()] +public class QuickRope2Prefab : MonoBehaviour +{ + public GameObject prefab = null; + public float jointScale = 1; + public bool alternateJoints = true; + public bool firstJointAlternated = false; + + private QuickRope2 rope; + + void OnEnable() + { + rope = GetComponent(); + + if (prefab == null) + prefab = (GameObject)Resources.Load("Link", typeof(GameObject)); + + rope.OnInitializeMesh += OnInitializeMesh; + } + + void OnDisable() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + void OnDestroy() + { + rope.OnInitializeMesh -= OnInitializeMesh; + if (rope != null) + rope.ClearJointObjects(); + } + + public void OnInitializeMesh() + { + if (!prefab) + return; + + //rope.FirstJointAlternated = firstJointAlternated; + //rope.AlternateJoints = alternateJoints; + rope.JointPrefab = prefab; + //rope.AlternateJoints = true; + rope.JointScale = jointScale; + rope.GenerateJointObjects(); + } + + /* + public void OnInsertJointAtStart() + { + Vector3 insertPos = rope.Joints[0].transform.position - ((rope.Joints[0].transform.position - rope.Joints[1].transform.position).normalized * rope.jointSpacing); + + GameObject go; + go = (GameObject)Instantiate(prefab, insertPos, rope.Joints[1].transform.rotation * Quaternion.Euler(0, 0, 90)); + go.transform.localScale = Vector3.one * jointScale; + + if (!rope.showJoints) + go.hideFlags = HideFlags.HideInHierarchy | HideFlags.NotEditable; + + if (go.collider) + go.collider.enabled = false; + + rope.Joints.Insert(1, go); + + rope.RebuildPhysics(); + } + */ +} diff --git a/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta new file mode 100644 index 0000000..442dce5 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/QuickRope2Prefab.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 83d36c9afb65c0646946a2815b5ed00d +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources.meta b/Assets/QuickRopes 2/CoreScripts/Resources.meta new file mode 100644 index 0000000..4201630 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 0965c7aa3122d4348a93f0a079cc0a60 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab new file mode 100644 index 0000000..d1a392e --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &100000 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 4 + m_Component: + - 4: {fileID: 400000} + - 33: {fileID: 3300000} + - 23: {fileID: 2300000} + - 65: {fileID: 6500000} + m_Layer: 0 + m_Name: Link + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &400000 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} +--- !u!23 &2300000 +Renderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_LightmapIndex: 255 + m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} + m_Materials: + - {fileID: 2100000, guid: 75e20fdf21ee4cd4bbbff5787612aa0f, type: 2} + m_SubsetIndices: + m_StaticBatchRoot: {fileID: 0} + m_UseLightProbes: 0 + m_LightProbeAnchor: {fileID: 0} + m_ScaleInLightmap: 1 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_SortingLayerID: 0 +--- !u!33 &3300000 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Mesh: {fileID: 4300002, guid: c8a4b06a79d2ea14cab2b7b100678259, type: 3} +--- !u!65 &6500000 +BoxCollider: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1.18778586, y: .251918912, z: 1.78015339} + m_Center: {x: -2.98023224e-08, y: 0, z: .465184152} +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 100000} + m_IsPrefabParent: 1 + m_IsExploded: 1 diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta new file mode 100644 index 0000000..e13dc87 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f3969805e3f8240449b2bace83fe0d22 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab new file mode 100644 index 0000000..a73d138 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab @@ -0,0 +1,70 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &100000 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 4 + m_Component: + - 4: {fileID: 400000} + - 33: {fileID: 3300000} + - 23: {fileID: 2300000} + m_Layer: 0 + m_Name: Link_NoCollide + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &400000 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} +--- !u!23 &2300000 +Renderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_LightmapIndex: 255 + m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} + m_Materials: + - {fileID: 2100000, guid: 75e20fdf21ee4cd4bbbff5787612aa0f, type: 2} + m_SubsetIndices: + m_StaticBatchRoot: {fileID: 0} + m_UseLightProbes: 0 + m_LightProbeAnchor: {fileID: 0} + m_ScaleInLightmap: 1 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_SortingLayerID: 0 +--- !u!33 &3300000 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 100000} + m_Mesh: {fileID: 4300002, guid: c8a4b06a79d2ea14cab2b7b100678259, type: 3} +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 100000} + m_IsPrefabParent: 1 + m_IsExploded: 1 diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta new file mode 100644 index 0000000..d2aa7ed --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Link_NoCollide.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ea151239cf8ec7a4d84611bb83692120 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta new file mode 100644 index 0000000..aef0fb5 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 08396fcaf129ad54b94d677712e75c0f +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat new file mode 100644 index 0000000..20d9f0d --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Rope + m_Shader: {fileID: 2, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: 8f91147309add1148949640554a73d05, type: 3} + m_Scale: {x: 9, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BumpMap + second: + m_Texture: {fileID: 2800000, guid: 7c5cdadd5ede8ac4baca46175ebb0272, type: 3} + m_Scale: {x: 20, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta new file mode 100644 index 0000000..869128d --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/Rope.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d13f5189a59c115459a78374b0d626ee +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat new file mode 100644 index 0000000..25d6cd1 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat @@ -0,0 +1,59 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: RopeLineMaterial + m_Shader: {fileID: 30, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 10.5, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BumpMap + second: + m_Texture: {fileID: 2800000, guid: e8bb5997f0222cf4ab984dd1ed405225, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + data: + first: + name: _Cutoff + second: .574626863 + data: + first: + name: _InvFade + second: 1 + data: + first: + name: _Shininess + second: .699999988 + m_Colors: + data: + first: + name: _Color + second: {r: 0, g: 0, b: 0, a: 1} + data: + first: + name: _TintColor + second: {r: .0895522237, g: .0895522237, b: .0895522237, a: .501960814} + data: + first: + name: _SpecColor + second: {r: 1, g: 1, b: 1, a: 1} + data: + first: + name: _Emission + second: {r: 0, g: 0, b: 0, a: 0} diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta new file mode 100644 index 0000000..2491c84 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/RopeLineMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 7455cdddd8cf6884fb8c267adb8e046e +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat new file mode 100644 index 0000000..a939cb4 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: WhiteLink + m_Shader: {fileID: 3, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + data: + first: + name: _Shininess + second: .537442207 + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: 1, a: 1} + data: + first: + name: _SpecColor + second: {r: .907406926, g: .910447776, b: .801737607, a: 1} diff --git a/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta new file mode 100644 index 0000000..00cb542 --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/Resources/Materials/WhiteLink.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 75e20fdf21ee4cd4bbbff5787612aa0f +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs new file mode 100644 index 0000000..bdebcea --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs @@ -0,0 +1,515 @@ + +using UnityEngine; +using System.Collections; + + +public class RopeTubeRenderer +{ + public bool calculateTangents = false; // turn off to boost performance, results in odd reflections + + GameObject _gameObject; + public GameObject gameObject { get { return _gameObject; } } + + Transform _transform; + public Transform transform { get { return _transform; } } + + int targetVertexCount; // points.Length * ( edgeCount+1 ) one extra hidden edge for UV wrapping + + // user manipulated variables // + Vector3[] points = new Vector3[0]; + float radius = 0.5f; + float[] radiuses; + int edgeCount = 12; // minimum is three + Color[] pointColors; + Rect capUVRect = new Rect(0, 0, 1, 1); + Rect bodyUVRect = new Rect(0, 0, 1, 1); + + // internal variables // + Vector3[] vertices = new Vector3[0]; + Vector3[] normals = new Vector3[0]; + int[] triangles; + Vector2[] uvs; + Vector4[] tangents = new Vector4[0]; + Color[] colors; + Vector3[] circleLookup; + Quaternion[] rotations = new Quaternion[0]; + + MeshFilter filter; + + bool updateCircleLookupFlag; + bool updateUVsFlag; + bool updateTrianglesFlag; + bool updateTangentsFlag; + bool updateColorsFlag; + bool redrawFlag; + + bool pointCountChanged; + + const float TWO_PI = Mathf.PI * 2; + + Vector3 pastUp; // used for calculating the rotation + public Vector3 up + { + get { return pastUp != Vector3.zero ? pastUp : Vector3.up; } + set { pastUp = value; } + + } + + private Mesh _mesh; + public Mesh mesh + { + get { return _mesh; } + } + + + public RopeTubeRenderer(GameObject _gameObject, bool useMeshOnly) + { + if (!useMeshOnly) + { + this._gameObject = _gameObject; + this._transform = _gameObject.transform; + + // ensure necessary components // + MeshFilter filter = _gameObject.GetComponent(); + if (filter == null) filter = _gameObject.AddComponent(); + MeshRenderer renderer = _gameObject.GetComponent(); + if (renderer == null) renderer = _gameObject.AddComponent(); + + _mesh = new Mesh(); + _mesh.name = "RopeTube_" + _gameObject.GetInstanceID(); + filter.mesh = _mesh; + + if (renderer.sharedMaterial == null) + renderer.sharedMaterial = (Material)Resources.Load("Materials/Rope", typeof(Material)); + } + else + { + this._gameObject = _gameObject; + this._transform = _gameObject.transform; + + _mesh = new Mesh(); + _mesh.name = "RopeTube_" + _gameObject.GetInstanceID(); + } + } + + + public void Update() + { + if (points.Length == 0) return; + + if (updateCircleLookupFlag) { UpdateCircleLookup(); } + if (updateUVsFlag) { UpdateUVs(); } + if (updateTangentsFlag && calculateTangents) { UpdateTangents(); } + if (updateTrianglesFlag) { UpdateTriangles(); } + if (redrawFlag) { ReDraw(); } + if (updateColorsFlag) { UpdateColors(); } + + updateCircleLookupFlag = false; + updateTangentsFlag = false; + updateTrianglesFlag = false; + updateUVsFlag = false; + redrawFlag = false; + updateColorsFlag = false; + } + + + void ReDraw() + { + // update array length // + if (vertices.Length != targetVertexCount) + { + _mesh.triangles = new int[0]; // avoid "Mesh.vertices is too small" error message + vertices = new Vector3[targetVertexCount]; + } + if (normals.Length != targetVertexCount) normals = new Vector3[targetVertexCount]; + + int v = 1 + edgeCount + 1; // start beyond the start cap + + Vector3 minBounds = new Vector3(10000, 10000, 10000); + Vector3 maxBounds = new Vector3(-10000, -10000, -10000); + for (int p = 0; p < points.Length; p++) + { + //rotations[p] *= Quaternion.Euler(0, 90, 0); + + if (radiuses != null) + { + // check min an max bounds // + if (points[p].x - radiuses[p] < minBounds.x) minBounds.x = points[p].x - radiuses[p]; + if (points[p].y - radiuses[p] < minBounds.y) minBounds.y = points[p].y - radiuses[p]; + if (points[p].z - radiuses[p] < minBounds.z) minBounds.z = points[p].z - radiuses[p]; + if (points[p].x + radiuses[p] > maxBounds.x) maxBounds.x = points[p].x + radiuses[p]; + if (points[p].y + radiuses[p] > maxBounds.y) maxBounds.y = points[p].y + radiuses[p]; + if (points[p].z + radiuses[p] > maxBounds.z) maxBounds.z = points[p].z + radiuses[p]; + + // set vertices and normals // + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = _transform.InverseTransformPoint(points[p] + rotations[p] * circleLookup[s] * radiuses[p]); + normals[v] = _transform.InverseTransformDirection(rotations[p] * circleLookup[s]); + v++; + } + + } + else + { + // check min an max bounds // + if (points[p].x - radius < minBounds.x) minBounds.x = points[p].x - radius; + if (points[p].y - radius < minBounds.y) minBounds.y = points[p].y - radius; + if (points[p].z - radius < minBounds.z) minBounds.z = points[p].z - radius; + if (points[p].x + radius > maxBounds.x) maxBounds.x = points[p].x + radius; + if (points[p].y + radius > maxBounds.y) maxBounds.y = points[p].y + radius; + if (points[p].z + radius > maxBounds.z) maxBounds.z = points[p].z + radius; + + // set vertices and normals // + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = _transform.InverseTransformPoint(points[p] + rotations[p] * circleLookup[s] * radius); + normals[v] = _transform.InverseTransformDirection(rotations[p] * circleLookup[s]); + v++; + } + } + } + + // start and end caps // + vertices[0] = _transform.InverseTransformPoint(points[0]); + vertices[vertices.Length - 1] = _transform.InverseTransformPoint(points[points.Length - 1]); + normals[0] = _transform.InverseTransformDirection(rotations[0] * Vector3.forward); + normals[targetVertexCount - 1] = _transform.InverseTransformDirection(rotations[0] * -Vector3.forward); + v = 1; + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = vertices[v + edgeCount + 1]; + normals[v] = normals[0]; + v++; + } + v = vertices.Length - edgeCount - 2; + for (int s = 0; s < edgeCount + 1; s++) + { + vertices[v] = vertices[v - edgeCount - 1]; + normals[v] = normals[targetVertexCount - 1]; + v++; + } + + // update mesh // + _mesh.vertices = vertices; + if (updateUVsFlag) _mesh.uv = uvs; + if (updateTrianglesFlag) _mesh.triangles = triangles; + _mesh.normals = normals; + if (calculateTangents) _mesh.tangents = tangents; + + /* + // update bounds // + Vector3 boundsSize = new Vector3(maxBounds.x - minBounds.x, maxBounds.y - minBounds.y, maxBounds.z - minBounds.z); + Vector3 boundsCenter = new Vector3(minBounds.x + boundsSize.x * 0.5f, minBounds.y + boundsSize.y * 0.5f, minBounds.z + boundsSize.z * 0.5f); + _mesh.bounds = new Bounds(boundsCenter, boundsSize); + + */ + _mesh.RecalculateBounds(); + } + + + void UpdateCircleLookup() + { + circleLookup = new Vector3[edgeCount + 1]; // add one more hidden side for UV wrapping + float interpolatorMult = 1 / (float)edgeCount; + for (int s = 0; s < circleLookup.Length; s++) + { + float interpolator = s * interpolatorMult * TWO_PI; + circleLookup[s] = new Vector3(0, Mathf.Cos(interpolator), Mathf.Sin(interpolator)); + } + } + + + void UpdateUVs() + { + uvs = new Vector2[targetVertexCount]; + float interpolatorUmult = 1 / (points.Length - 1f); + float interpolatorVmult = 1 / (float)edgeCount; + int uv = 0; + // start cap // + uvs[uv++] = new Vector2(capUVRect.width * 0.5f + capUVRect.x, capUVRect.height * 0.5f + capUVRect.y); + for (int v = 0; v < edgeCount + 1; v++) + { + float angle = v * interpolatorVmult * TWO_PI + Mathf.PI * 0.5f; + uvs[uv++] = new Vector2(uvs[0].x + Mathf.Cos(angle) * 0.5f * capUVRect.width, uvs[0].y + Mathf.Sin(angle) * 0.5f * capUVRect.height); + } + // body // + for (int u = 0; u < points.Length; u++) + { + float interpolatorU = u * interpolatorUmult; + for (int v = 0; v < edgeCount + 1; v++) + { + float interpolatorV = v * interpolatorVmult; + uvs[uv++] = new Vector2(bodyUVRect.x + interpolatorU * bodyUVRect.width, bodyUVRect.y + interpolatorV * bodyUVRect.height); + } + } + // end cap // + for (int v = 0; v < edgeCount + 1; v++) uvs[uv++] = uvs[v + 1]; + uvs[uv++] = uvs[0]; + } + + + void UpdateTangents() + { + tangents = new Vector4[targetVertexCount]; + int t = 0; + // start cap // + Vector3 tangent = _transform.InverseTransformDirection(rotations[0] * Vector3.right); + for (int s = 0; s < edgeCount + 2; s++) + { + tangents[t++] = new Vector4(tangent.x, tangent.y, tangent.z, 1); + } + // body // + for (int r = 0; r < rotations.Length; r++) + { + tangent = _transform.InverseTransformDirection(rotations[r] * Vector3.forward); + if (calculateTangents) + { + for (int s = 0; s < edgeCount + 1; s++) + { + tangents[t++] = new Vector4(tangent.x, tangent.y, tangent.z, 1); + } + } + } + // end cap // + tangent = _transform.InverseTransformDirection(rotations[rotations.Length - 1] * Vector3.left); + for (int s = 0; s < edgeCount + 2; s++) + { + tangents[t++] = new Vector4(tangent.x, tangent.y, tangent.z, 1); + } + } + + + void UpdateTriangles() + { + int bodyTriangleCount = (points.Length - 1) * edgeCount * 2; + int capsTriangleCount = 2 * edgeCount; + triangles = new int[(bodyTriangleCount + capsTriangleCount) * 3]; + int v = 1; int t = 0; + // begin cap // + for (int e = 0; e < edgeCount; e++) + { + triangles[t++] = v + 1; + triangles[t++] = v; + triangles[t++] = 0; + v++; + } + v++; // skip hidden vertex + + // body // + int[] quad = new int[] { 0, 1, edgeCount + 2, 0, edgeCount + 2, edgeCount + 1 }; + for (int p = 0; p < points.Length - 1; p++) + { + for (int e = 0; e < edgeCount; e++) + { + for (int q = 0; q < quad.Length; q++) triangles[t++] = v + quad[q]; + v++; + } + v++; // skip hidden vertex + } + + v++; // skip hidden vertex + v += edgeCount; // move to next band + + // end cap // + for (int e = 0; e < edgeCount; e++) + { + + triangles[t++] = v; + triangles[t++] = v + 1; + triangles[t++] = targetVertexCount - 1; + v++; + } + } + + + void UpdateColors() + { + if (pointColors != null) + { + colors = new Color[targetVertexCount]; + // cap start // + int v = 0; + colors[v++] = pointColors[0]; + for (int s = 0; s < edgeCount + 1; s++) colors[v++] = pointColors[0]; + + // body // + for (int p = 0; p < points.Length; p++) + { + for (int s = 0; s < edgeCount + 1; s++) + { + colors[v++] = pointColors[p]; + } + } + // cap end // + for (int s = 0; s < edgeCount + 1; s++) + { + colors[v++] = pointColors[pointColors.Length - 1]; + } + colors[v++] = pointColors[pointColors.Length - 1]; + + mesh.colors = colors; + } + } + + + //////////// + // PUBLIC // + //////////// + + + public void SetPointCount(int pointCount) + { + if (pointCount < 2) + { + Debug.LogWarning("TubeRenderer must have at two three points."); + return; + } + + updateTrianglesFlag = true; + updateUVsFlag = true; + updateColorsFlag = true; + updateTangentsFlag = true; + if (circleLookup == null) updateCircleLookupFlag = true; + redrawFlag = true; + + targetVertexCount = pointCount * (edgeCount + 1); + + this.points = new Vector3[pointCount]; + } + + + public void SetPointsAndRotations(Vector3[] points, Quaternion[] rotations) + { + if (points.Length < 2) + { + Debug.LogWarning("RopeTubeRenderer must have at two three points."); + return; + } + + if (points.Length != rotations.Length) + { + Debug.LogWarning("point array must match length of rotation array."); + return; + } + + int lastPointCount = (this.points != null) ? this.points.Length : 0; + if (points.Length != lastPointCount) + { + updateTrianglesFlag = true; + updateUVsFlag = true; + updateColorsFlag = true; + } + updateTangentsFlag = true; + if (circleLookup == null) updateCircleLookupFlag = true; + redrawFlag = true; + + if (radiuses != null) if (points.Length != radiuses.Length) radiuses = null; + + targetVertexCount = (points.Length + 2) * (edgeCount + 1) + 2; // two cap end points + + this.points = points; + this.rotations = rotations; + } + + + public void SetEdgeCount(int edgeCount) + { + if (edgeCount < 3) edgeCount = 3; + + this.edgeCount = edgeCount; + + updateTrianglesFlag = true; + updateUVsFlag = true; + updateCircleLookupFlag = true; + updateColorsFlag = true; + redrawFlag = true; + + targetVertexCount = (points.Length + 2) * (edgeCount + 1) + 2; // two end points + } + + + public void SetRadius(float radius) + { + this.radius = radius; + + redrawFlag = true; + } + + + public void SetRadiuses(float[] radiuses) + { + if (radiuses == null) + { + this.radiuses = null; + return; + } + if (radiuses.Length != points.Length) + { + Debug.Log( + "TubeRenderer only receives as many radius values as it has points. " + + "Use SetPoints() or SetPointCount() before using SetRadiuses()" + ); + return; + } + + this.radiuses = radiuses; + + redrawFlag = true; + } + + + public void SetColors(Color[] colors) + { + if (colors.Length != points.Length) + { + Debug.Log( + "TubeRenderer only receives as many color values as it has points. " + + "Use SetPoints() or SetPointCount() before using SetColors()" + ); + return; + } + pointColors = colors; + + updateColorsFlag = true; + } + + + public void SetBodyUVRect(Rect uvRect) + { + bodyUVRect = uvRect; + + updateUVsFlag = true; + } + + + public void SetCapsUVRect(Rect uvRect) + { + capUVRect = uvRect; + + updateUVsFlag = true; + } + + + // GETTERS // + + + public Vector3[] Points() + { + Vector3[] copy = new Vector3[points.Length]; + points.CopyTo(copy, 0); + return copy; + } + + + public float[] Radiuses() + { + float[] copy = new float[radiuses.Length]; + radiuses.CopyTo(copy, 0); + return copy; + } + + + public int EdgeCount() { return edgeCount; } + +} \ No newline at end of file diff --git a/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta new file mode 100644 index 0000000..6d047bd --- /dev/null +++ b/Assets/QuickRopes 2/CoreScripts/RopeTubeRenderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ad8ba11caaa438a47864ec0880ddaff2 +labels: +- editor +- physics +- chain +- string +- cable +- reverie +- interactive +- quickropes +- gameplay +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/QuickRopes 2/FBX_Files.meta b/Assets/QuickRopes 2/FBX_Files.meta new file mode 100644 index 0000000..7256485 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8b10706508803fa4a90cc64a38846e6d +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane.meta b/Assets/QuickRopes 2/FBX_Files/Crane.meta new file mode 100644 index 0000000..e47b946 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f68c639223b4abe42b8cd932d8662715 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx new file mode 100644 index 0000000..f99e5f6 Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta new file mode 100644 index 0000000..7b72597 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneBase.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: 51ed34cb4553e7843a7037671e00edf3 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface14 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx new file mode 100644 index 0000000..b9370bb Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta new file mode 100644 index 0000000..8325e0f --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneCab.fbx.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 1c68057bd2844a844820ab2d037fd22f +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: Cab1 + 100002: //RootNode + 400000: Cab1 + 400002: //RootNode + 2300000: Cab1 + 2300002: //RootNode + 3300000: Cab1 + 3300002: //RootNode + 4300000: CabBase + 4300002: Cab1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx new file mode 100644 index 0000000..f42077e Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta new file mode 100644 index 0000000..e2c755c --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneHook.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: ebbeb2f1e7f8ccc40accd54fc043696c +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: pCube1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx new file mode 100644 index 0000000..ab43bad Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta new file mode 100644 index 0000000..fa88ca6 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/CraneSegment.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: e7e3bed7953f28f4289b0ea1e0556548 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface32 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .5 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta new file mode 100644 index 0000000..3ab5490 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 193cc445caa9a48c293cd09f95260d84 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat new file mode 100644 index 0000000..928c044 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: BlackSteel + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .197999999, g: .197999999, b: .197999999, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta new file mode 100644 index 0000000..0540dbb --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/BlackSteel.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5a4f8fbee1ff241c3820d0a888ae34bb +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat new file mode 100644 index 0000000..bd94d7e --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Cab + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .889999986, g: .889999986, b: .889999986, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta new file mode 100644 index 0000000..8f5b7b1 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Cab.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: f7c503e4856d046b69fdc74c4cc501f3 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat new file mode 100644 index 0000000..a21f874 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: CabGlass + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .122000001, g: .122000001, b: .122000001, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta new file mode 100644 index 0000000..262a2d9 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/CabGlass.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ebab5ecf39fd64d5a9e51424372f7b28 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat new file mode 100644 index 0000000..ba1fbfa --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Concrete + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .779999971, g: .779999971, b: .779999971, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta new file mode 100644 index 0000000..520fb82 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Concrete.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3c02602ec924342b0bc2c4b71ad2c673 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat new file mode 100644 index 0000000..e6f5ec3 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Hook + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .827344179, g: .827344179, b: .827344179, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta new file mode 100644 index 0000000..4091a0c --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/Hook.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5e662d9f538f04321ac24a54be5e2fd4 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat new file mode 100644 index 0000000..f01d02a --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: RedHook5556 + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .5, g: .113999993, b: .113999993, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta new file mode 100644 index 0000000..f96a40b --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/RedHook5556.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0598d3744fc714a3a93dd3c3a5997cbc +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat new file mode 100644 index 0000000..3904e23 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: YellowSteel + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: .893616676, b: .509000003, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta new file mode 100644 index 0000000..17e419a --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Crane/Materials/YellowSteel.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d939c6f2adce04433afbab64a54c9fe3 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Gear.fbx b/Assets/QuickRopes 2/FBX_Files/Gear.fbx new file mode 100644 index 0000000..f3f7e68 Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Gear.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta new file mode 100644 index 0000000..2863487 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Gear.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: e8983cfbcbd91c14ebb3e84a77527d98 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Lamp.fbx b/Assets/QuickRopes 2/FBX_Files/Lamp.fbx new file mode 100644 index 0000000..1bd3815 Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Lamp.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Lamp.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Lamp.fbx.meta new file mode 100644 index 0000000..64f2c4b --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Lamp.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: 79c50f16855dc5341ac5648553fdd246 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface13 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx b/Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx new file mode 100644 index 0000000..67b8d42 Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx.meta b/Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx.meta new file mode 100644 index 0000000..a71c54e --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Link_FBX.fbx.meta @@ -0,0 +1,66 @@ +fileFormatVersion: 2 +guid: c8a4b06a79d2ea14cab2b7b100678259 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 100002: pasted__Link + 400000: //RootNode + 400002: pasted__Link + 2300000: pasted__Link + 3300000: pasted__Link + 4300000: Link + 4300002: pasted__Link + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 0 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .600000024 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Materials.meta b/Assets/QuickRopes 2/FBX_Files/Materials.meta new file mode 100644 index 0000000..9644dd3 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a980ba19d95634c31ba608535ac0d43f +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat b/Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat new file mode 100644 index 0000000..8907915 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: BlackMetal1 + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .186999306, g: .186999306, b: .186999306, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat.meta b/Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat.meta new file mode 100644 index 0000000..e6918b8 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/BlackMetal1.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: bb52a3732e8554180a81b128ff850fd2 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat b/Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat new file mode 100644 index 0000000..1d60278 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: LitPaper + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: .80392158, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat.meta b/Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat.meta new file mode 100644 index 0000000..c896042 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/LitPaper.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3cfec6945a64e402fa6eca73c99c1a6e +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat b/Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat new file mode 100644 index 0000000..86bd8fb --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Rust_Scale + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat.meta b/Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat.meta new file mode 100644 index 0000000..5d11dcf --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/Rust_Scale.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 30a869a0054b8479087067333120cd64 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat b/Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat new file mode 100644 index 0000000..6c7eb88 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Wood + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .647058845, g: .490194172, b: .266435981, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat.meta b/Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat.meta new file mode 100644 index 0000000..1c47674 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/Wood.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: dd7a5ca7e1a604f9784f37ca6bd65afc +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat b/Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat new file mode 100644 index 0000000..428b26b --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: lambert1 + m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: [] + m_CustomRenderQueue: -1 + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: .5, g: .5, b: .5, a: 1} diff --git a/Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat.meta b/Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat.meta new file mode 100644 index 0000000..964b6b1 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/Materials/lambert1.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: fa01dbdb76f0d45df89d9474fdd11ab7 +NativeFormatImporter: + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx b/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx new file mode 100644 index 0000000..04b5f89 Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta b/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta new file mode 100644 index 0000000..0489885 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/PlanetaryGearSet.fbx.meta @@ -0,0 +1,83 @@ +fileFormatVersion: 2 +guid: 4ffdbdeb1c2bc5a429813bda18cf05a5 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100002: //RootNode + 100010: InnerRing_Motor + 100012: Small_Gear + 100014: OutterRing_Gear + 400002: //RootNode + 400010: InnerRing_Motor + 400012: Small_Gear + 400014: OutterRing_Gear + 2300000: InnerRing_Motor + 2300002: Small_Gear + 2300004: OutterRing_Gear + 3300000: InnerRing_Motor + 3300002: Small_Gear + 3300004: OutterRing_Gear + 4300000: pPipe1 + 4300002: pPipe2 + 4300004: pPipe5 + 4300006: polySurface2 + 4300008: OutterRing_Gear + 4300010: InnerRing_Motor + 4300012: Small_Gear + 4300014: pasted__Link + 4300016: pasted__Link + 4300018: pasted__Link + 4300020: pasted__Link + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx b/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx new file mode 100644 index 0000000..4583ca5 Binary files /dev/null and b/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx differ diff --git a/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx.meta b/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx.meta new file mode 100644 index 0000000..a57cdd1 --- /dev/null +++ b/Assets/QuickRopes 2/FBX_Files/RustyHook.fbx.meta @@ -0,0 +1,63 @@ +fileFormatVersion: 2 +guid: f2756becdad5eff4981e16a00cda0cd7 +ModelImporter: + serializedVersion: 15 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: polySurface1 + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 1 + userData: diff --git a/Assets/Scripts/Fie/Camera/FieCameraBase.cs b/Assets/Scripts/Fie/Camera/FieCameraBase.cs index d218a69..4834b5b 100644 --- a/Assets/Scripts/Fie/Camera/FieCameraBase.cs +++ b/Assets/Scripts/Fie/Camera/FieCameraBase.cs @@ -57,11 +57,11 @@ namespace Fie.Camera PostProcessingBehaviour component = GetComponent(); AmplifyBloomEffect component2 = GetComponent(); UltimateBloom component3 = GetComponent(); - SSREffect component4 = GetComponent(); + //SSREffect component4 = GetComponent(); PKFxRenderingPlugin component5 = GetComponent(); SunShafts component6 = GetComponent(); SEGI component7 = GetComponent(); - VolumetricFog component8 = GetComponent(); + //VolumetricFog component8 = GetComponent(); FieCommandBufferReflection component9 = GetComponent(); switch (qualityLevel) { @@ -78,10 +78,10 @@ namespace Fie.Camera { component3.enabled = false; } - if (component4 != null) - { - component4.enabled = false; - } + // if (component4 != null) + // { + // component4.enabled = false; + // } if (component5 != null) { component5.m_EnableDistortion = false; @@ -98,10 +98,10 @@ namespace Fie.Camera { component7.enabled = false; } - if (component8 != null) - { - component8.enabled = false; - } + // if (component8 != null) + // { + // component8.enabled = false; + // } if (component9 != null) { component9.enabled = false; @@ -117,10 +117,10 @@ namespace Fie.Camera { component3.enabled = false; } - if (component4 != null) - { - component4.enabled = false; - } + // if (component4 != null) + // { + // component4.enabled = false; + // } if (component5 != null) { component5.m_EnableDistortion = false; @@ -137,10 +137,10 @@ namespace Fie.Camera { component7.enabled = false; } - if (component8 != null) - { - component8.enabled = false; - } + // if (component8 != null) + // { + // component8.enabled = false; + // } if (component9 != null) { component9.enabled = false; @@ -160,10 +160,10 @@ namespace Fie.Camera { component3.enabled = true; } - if (component4 != null) - { - component4.enabled = false; - } + // if (component4 != null) + // { + // component4.enabled = false; + // } if (component5 != null) { component5.m_EnableDistortion = true; @@ -184,10 +184,10 @@ namespace Fie.Camera { component.profile = PostProcessingProfileForLev3; } - if (component8 != null) - { - component8.enabled = false; - } + // if (component8 != null) + // { + // component8.enabled = false; + // } if (component9 != null) { component9.enabled = true; @@ -207,10 +207,10 @@ namespace Fie.Camera { component3.enabled = true; } - if (component4 != null) - { - component4.enabled = true; - } + // if (component4 != null) + // { + // component4.enabled = true; + // } if (component5 != null) { component5.m_EnableDistortion = true; @@ -231,10 +231,10 @@ namespace Fie.Camera { component.profile = PostProcessingProfileForLev4; } - if (component8 != null) - { - component8.enabled = true; - } + // if (component8 != null) + // { + // component8.enabled = true; + // } if (component9 != null) { component9.enabled = true; @@ -254,10 +254,10 @@ namespace Fie.Camera { component3.enabled = true; } - if (component4 != null) - { - component4.enabled = true; - } + // if (component4 != null) + // { + // component4.enabled = true; + // } if (component5 != null) { component5.m_EnableDistortion = true; @@ -278,10 +278,10 @@ namespace Fie.Camera { component.profile = PostProcessingProfileForLev5; } - if (component8 != null) - { - component8.enabled = true; - } + // if (component8 != null) + // { + // component8.enabled = true; + // } if (component9 != null) { component9.enabled = true; diff --git a/Assets/Scripts/Fie/Title/FieTitleAuthController.cs b/Assets/Scripts/Fie/Title/FieTitleAuthController.cs index e49603f..57cafd9 100644 --- a/Assets/Scripts/Fie/Title/FieTitleAuthController.cs +++ b/Assets/Scripts/Fie/Title/FieTitleAuthController.cs @@ -1,5 +1,5 @@ using Fie.Manager; -using MBS; +//using MBS; using UnityEngine; namespace Fie.Title @@ -15,8 +15,8 @@ namespace Fie.Title UNNECESSARY } - [SerializeField] - private WUUGLoginGUI _loginGUIComponent; + //[SerializeField] + //private WUUGLoginGUI _loginGUIComponent; public event FinishedLoginProcessCallback finishedEvent; @@ -26,14 +26,14 @@ namespace Fie.Title { return RecomendedLoginState.UNNECESSARY; } - if (WULogin.logged_in) - { - if (!PhotonNetwork.connected) - { - return RecomendedLoginState.CONNECT_TO_MASTER; - } - return RecomendedLoginState.UNNECESSARY; - } + // if (WULogin.logged_in) + // { + // if (!PhotonNetwork.connected) + // { + // return RecomendedLoginState.CONNECT_TO_MASTER; + // } + // return RecomendedLoginState.UNNECESSARY; + // } return RecomendedLoginState.AUTH; } @@ -42,9 +42,9 @@ namespace Fie.Title switch (recomendedState) { case RecomendedLoginState.AUTH: - _loginGUIComponent.gameObject.SetActive(value: true); - _loginGUIComponent.InitWULoginGUI(); - _loginGUIComponent.loginEvent += _loginGUIComponent_loginCallback; + // _loginGUIComponent.gameObject.SetActive(value: true); + // _loginGUIComponent.InitWULoginGUI(); + // _loginGUIComponent.loginEvent += _loginGUIComponent_loginCallback; break; case RecomendedLoginState.CONNECT_TO_MASTER: FieManagerBehaviour.I.connectedToMasterServerEvent += _connectedToMasterServerCallback; diff --git a/fie.csproj b/fie.csproj index 37f5c90..3af0ebf 100644 --- a/fie.csproj +++ b/fie.csproj @@ -2316,6 +2316,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +