diff --git a/Assets/ArtRes/3D/Fish/fish_red_tail_barracuda/Material/fish_red_tail_barracuda_mat_ll.mat b/Assets/ArtRes/3D/Fish/fish_red_tail_barracuda/Material/fish_red_tail_barracuda_mat_ll.mat index c5e3e76..61d4351 100644 --- a/Assets/ArtRes/3D/Fish/fish_red_tail_barracuda/Material/fish_red_tail_barracuda_mat_ll.mat +++ b/Assets/ArtRes/3D/Fish/fish_red_tail_barracuda/Material/fish_red_tail_barracuda_mat_ll.mat @@ -21,7 +21,7 @@ Material: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: fish_red_tail_barracuda_mat_ll - m_Shader: {fileID: 4800000, guid: 5626fadf5ea58ad448d468c2362fadfb, type: 3} + m_Shader: {fileID: 4800000, guid: 8e32954102c0fc647a751090ef5e40be, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 m_ValidKeywords: [] diff --git a/Assets/Scenes/Oasis/OasisScene.unity b/Assets/Scenes/Oasis/OasisScene.unity index 5725beb..7c02b65 100644 --- a/Assets/Scenes/Oasis/OasisScene.unity +++ b/Assets/Scenes/Oasis/OasisScene.unity @@ -22509,7 +22509,7 @@ MeshRenderer: m_RendererPriority: 0 m_Materials: - {fileID: 2100000, guid: 82f089674b537fe42b84f66f22c4b13f, type: 2} - - {fileID: 2100000, guid: 2d10684597fead649b048a865154ad79, type: 2} + - {fileID: 2100000, guid: 872b4d67fd3bbd14caa9aea720bd1b75, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -22548,7 +22548,7 @@ Transform: m_GameObject: {fileID: 1335403876} serializedVersion: 2 m_LocalRotation: {x: 0.000000018075937, y: -0.5621158, z: -0.000000012285431, w: 0.8270586} - m_LocalPosition: {x: -1.386, y: 1.0068, z: -116.992} + m_LocalPosition: {x: -1.3689, y: 1, z: -116.9988} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -29247,7 +29247,7 @@ Transform: m_GameObject: {fileID: 1829397597} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -3.221, y: 0.89, z: -116.13} + m_LocalPosition: {x: -3.221, y: 1.712, z: -116.13} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -33661,7 +33661,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!4 &2128448439 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl b/Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl new file mode 100644 index 0000000..c8dba93 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl @@ -0,0 +1,110 @@ +#include "MomentOutput.hlsl" + +// DONTBLOWUP is NOT part of the original paper, this is a hack i had to do to make this implementation usable + +//#define ABSORPTION_EPSILON max(REAL_MIN, 1e-5) +#if _MOMENT_HALF_PRECISION +//#define DONTBLOWUP HALF_MIN +#define DONTBLOWUP HALF_EPS +#else +//#define DONTBLOWUP FLT_MIN +#define DONTBLOWUP FLT_EPS +#endif + +float4 _WrappingZoneParameters; +/*! This function implements complex multiplication.*/ +float2 Multiply(float2 LHS, float2 RHS) { + return float2(LHS.x * RHS.x - LHS.y * RHS.y, LHS.x * RHS.y + LHS.y * RHS.x); +} + +// if ROV, set to the stored moments from the rasterizer order view and write the new moments back +// no ROVs so only single precision works - needs further changes for quantized to read/write moments +MomentOutput GenerateMoments(float vd, float t) +{ + t = max(t, DONTBLOWUP); // we have a blowup issue when t (1 - alpha) is close to 0, empirically it happens above 0.99 alpha so let's lock it around there (no visual issues, at that point its pretty indiscernable from opaque) + + // Return early if the surface is fully transparent + clip(0.9999999f - t); + + float a = -log(t); + float d = WarpDepth(vd); + + MomentOutput output; + output.b0 = a; + +#ifdef _TRIGONOMETRIC + float p = mad(d, _WrappingZoneParameters.y, _WrappingZoneParameters.y); + float2 c; + sincos(p, c.y, c.x); + float2 c2 = Multiply(c, c); + output.b1 = float4(c, c2) * a; +#ifdef _MOMENT8 + output.b2 = float4(Multiply(c, c2), Multiply(c2, c2)) * a; +#elif defined(_MOMENT6) + output.b2 = Multiply(c, c2) * a; +#endif +#else // not _TRIGONOMETRIC + float d2 = d * d; + float d4 = d2 * d2; + +#if _MOMENT_HALF_PRECISION // QUANTIZE (ROVs ONLY) +#ifdef _MOMENT8 + float4 b_even = (float4) 0; + float4 b_odd = (float4) 0;; + offsetMoments(b_even, b_odd, -1.0); + b_even *= output.b0; + b_odd *= output.b0; + + float d6 = d4 * d2; + float4 b_even_new = float4(d2, d4, d6, d6 * d2); + float4 b_odd_new = float4(d, d2 * d, d4 * d, d6 * d); + float4 b_even_new_q, b_odd_new_q; +#elif defined(_MOMENT6) + float3 b_even = (float3) 0; + float3 b_odd = (float3) 0; + offsetMoments(b_even, b_odd, -1.0); + b_even *= output.b0; + b_odd *= output.b0; + + float3 b_even_new = float3(d2, d4, d4 * d2); + float3 b_odd_new = float3(d, d2 * d, d4 * d); + float3 b_even_new_q, b_odd_new_q; +#else // _MOMENT4 + float2 b_even = (float2) 0; + float2 b_odd = (float2) 0; + offsetMoments(b_even, b_odd, -1.0); + b_even *= output.b0; + b_odd *= output.b0; + + float2 b_even_new = float2(d2, d4); + float2 b_odd_new = float2(d, d2 * d); + float2 b_even_new_q, b_odd_new_q; +#endif + + quantizeMoments(b_even_new_q, b_odd_new_q, b_even_new, b_odd_new); + // combine moments + b_even += b_even_new_q * a; + b_odd += b_odd_new_q * a; + // go back to interval [0, 1] + b_even /= a; + b_odd /= a; + offsetMoments(b_even, b_odd, 1.0); + output.b1 = float4(b_odd.x, b_even.x, b_odd.y, b_even.y); +#ifdef _MOMENT8 + output.b2 = float4(b_odd.z, b_even.z, b_odd.w, b_even.w); +#elif defined(_MOMENT6) + output.b2 = float2(b_odd.z, b_even.z); +#endif + +#else // _MOMENT_SINGLE_PRECISION + output.b1 = float4(d, d2, d2 * d, d4) * a; +#ifdef _MOMENT8 + output.b2 = output.b1 * d4; +#elif defined(_MOMENT6) + output.b2 = output.b1.xy * d4; +#endif +#endif // precision end +#endif // TRIGONOMETRIC end + + return output; +} \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl.meta new file mode 100644 index 0000000..828d1c6 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d94ff48de7281de41b27523cbe5b4b82 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat b/Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat new file mode 100644 index 0000000..3718edb --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Hidden_MOITComposite + m_Shader: {fileID: 4800000, guid: 1e94033f658200a4698edae134542fa2, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: [] + m_Ints: [] + m_Floats: + - _CATCHBIASERRORS: 0 + m_Colors: [] + m_BuildTextureStacks: [] diff --git a/Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat.meta b/Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat.meta new file mode 100644 index 0000000..a687467 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5b0014f90114064c8200b5c9ac93932 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITBias.cs b/Assets/Scripts/Features/OIT/MOIT/MOITBias.cs new file mode 100644 index 0000000..b0f90a7 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MOITBias.cs @@ -0,0 +1,36 @@ +using System; +using UnityEngine; + +[Serializable] +public class MOITBias +{ + // see supplementary document from the original paper : https://momentsingraphics.de/I3D2018.html ; Table 1 + + [Header("Power Moments")] + [Tooltip("Recommended : 6*10-5")] + public float Moments4Half = 0.00006f; + [Tooltip("Recommended : 5*10-7")] + public float Moments4Single = 0.0000005f; + [Tooltip("Recommended : 6*10-4")] + public float Moments6Half = 0.0006f; + [Tooltip("Recommended : 5*10-6")] + public float Moments6Single = 0.000005f; + [Tooltip("Recommended : 2.5*10-3")] + public float Moments8Half = 0.0025f; + [Tooltip("Recommended : 5*10-5")] + public float Moments8Single = 0.00005f; + + [Header("Trigonometric Moments")] + [Tooltip("(4 moments) Recommended : 4*10-4")] + public float Trigonometric2Half = 0.0004f; + [Tooltip("(4 moments) Recommended : 4*10-7")] + public float Trigonometric2Single = 0.0000004f; + [Tooltip("(6 moments) Recommended : 6.5*10-4")] + public float Trigonometric3Half = 0.00065f; + [Tooltip("(6 moments) Recommended : 8*10-7")] + public float Trigonometric3Single = 0.0000008f; + [Tooltip("(8 moments) Recommended : 8.5*10-4")] + public float Trigonometric4Half = 0.00085f; + [Tooltip("(8 moments) Recommended : 1.5*10-6")] + public float Trigonometric4Single = 0.0000015f; +} diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITBias.cs.meta b/Assets/Scripts/Features/OIT/MOIT/MOITBias.cs.meta new file mode 100644 index 0000000..8a19ae5 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MOITBias.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b50afbba4415dd24083a909b94e8ea98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader b/Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader new file mode 100644 index 0000000..cf2e608 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader @@ -0,0 +1,113 @@ +Shader "Hidden/MOITComposite" +{ + Properties + { + [Toggle] _CATCHBIASERRORS ("Catch Bias Errors", Float) = 0 // set this on if you see bloom fireflies and are not able to fix it with the other controls / are scared to see it again in build + } + + HLSLINCLUDE + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + // The Blit.hlsl file provides the vertex shader (Vert), + // the input structure (Attributes), and the output structure (Varyings) + #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" + + #ifdef _MOMENT_SINGLE_PRECISION + TEXTURE2D_FLOAT(_B0); + #else + TEXTURE2D_HALF(_B0); + #endif + //TEXTURE2D(_MOIT); // _MOIT is _BlitTexture since we don't need to sample screen tex (alpha blended) + + // sampler_PointClamp sampler_LinearClamp + #define singleSampler sampler_LinearClamp + + half4 MOITComposite(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + + //float4 moit = SAMPLE_TEXTURE2D(_BlitTexture, singleSampler, input.texcoord); + half4 moit = SAMPLE_TEXTURE2D(_BlitTexture, singleSampler, input.texcoord); + #ifdef _MOMENT_SINGLE_PRECISION + float b0 = SAMPLE_TEXTURE2D(_B0, singleSampler, input.texcoord).r; + #else + half b0 = SAMPLE_TEXTURE2D(_B0, singleSampler, input.texcoord).r; + #endif + moit.rgb /= moit.a; + + #if _CATCHBIASERRORS_ON + // catch negative color values when alpha is very close to 1 (>0.99) + // TODO: explore why the non shader graph tmpro shader writes negatives values in moit texture (in game view only) + return half4(max(moit.rgb, 0.0), exp(-b0)); + #else + return half4(moit.rgb, exp(-b0)); + #endif + } + + ENDHLSL + + SubShader + { + Tags{ "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" } + + ZWrite Off Cull Off + Pass + { + Name "Composite" + + ZTest Always + Blend OneMinusSrcAlpha SrcAlpha + + HLSLPROGRAM + + #pragma vertex Vert + #pragma fragment MOITComposite + + #pragma shader_feature _CATCHBIASERRORS_ON + + ENDHLSL + } + +// Pass +// { +// Name "CompositeFrameBuffer" +// +// ZTest Always +// Blend OneMinusSrcAlpha SrcAlpha +// +// HLSLPROGRAM +// +// #pragma vertex Vert +// #pragma fragment MOITCompositeFB +// +// #pragma shader_feature _CATCHBIASERRORS_ON +// +// FRAMEBUFFER_INPUT_X_FLOAT(0); +// +// half4 MOITCompositeFB(Varyings input) : SV_Target +// { +// UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); +// +// //float4 moit = SAMPLE_TEXTURE2D(_BlitTexture, singleSampler, input.texcoord); +// //float4 moit = LOAD_FRAMEBUFFER_X_INPUT(0, input.positionCS.xy); +// half4 moit = LOAD_FRAMEBUFFER_X_INPUT(0, input.positionCS.xy); +// #ifdef _MOMENT_SINGLE_PRECISION +// float b0 = SAMPLE_TEXTURE2D(_B0, singleSampler, input.texcoord).r; +// #else +// half b0 = SAMPLE_TEXTURE2D(_B0, singleSampler, input.texcoord).r; +// #endif +// moit.rgb /= moit.a; +// +// #if _CATCHBIASERRORS_ON +// // catch negative color values when alpha is very close to 1 (>0.99) +// // TODO: explore why the non shader graph tmpro shader writes negatives values in moit texture (in game view only) +// return half4(max(moit.rgb, 0.0), exp(-b0)); +// #else +// return half4(moit.rgb, exp(-b0)); +// #endif +// } +// +// ENDHLSL +// } + } +} diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader.meta b/Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader.meta new file mode 100644 index 0000000..33e94a4 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1e94033f658200a4698edae134542fa2 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITFeature.cs b/Assets/Scripts/Features/OIT/MOIT/MOITFeature.cs index 1c3cd92..eec6d46 100644 --- a/Assets/Scripts/Features/OIT/MOIT/MOITFeature.cs +++ b/Assets/Scripts/Features/OIT/MOIT/MOITFeature.cs @@ -1,14 +1,45 @@ using System; +using System.Drawing.Drawing2D; +using System.Runtime.ConstrainedExecution; +using System.Security.Cryptography; using UnityEngine; +using UnityEngine.Experimental.Rendering.RenderGraphModule; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; [DisallowMultipleRendererFeature("Moment Based Order-Independent Transparency")] public class MOITFeature : ScriptableRendererFeature { + public enum MomentsCount + { + _4 = 4, + _6 = 6, + _8 = 8 + } + + public enum FloatPrecision + { + _Half = 16, + _Single = 32 + } + + public enum BoundsType + { + NearFarPlanes, + FindObjects, + Register + // ideally add JustIterateThroughTheRendererListHandle at some point + } + [Serializable] class Settings { + [SerializeField] + internal RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingTransparents; + [SerializeField] + internal MOITSettings settings; + [SerializeField] + internal MOITBias biasSettings; } [SerializeField] @@ -32,17 +63,252 @@ public class MOITFeature : ScriptableRendererFeature pass = new(settings); } - class MOITPass : ScriptableRenderPass + protected override void Dispose(bool disposing) { - private Settings settings; + base.Dispose(disposing); + pass.Dispose(); + } + + class MOITPass : ScriptableRenderPass, IDisposable + { + private static readonly int b0TextureID = Shader.PropertyToID("_B0"); + private static readonly int b1TextureID = Shader.PropertyToID("_B1"); + private static readonly int b2TextureID = Shader.PropertyToID("_B2"); + private static readonly int logViewMinDeltaID = Shader.PropertyToID("_LogViewDepthMinDelta"); + private static readonly int wrappingZoneParametersID = Shader.PropertyToID("_WrappingZoneParameters"); + private static readonly int biasID = Shader.PropertyToID("_MOIT_MomentBias"); + private static readonly int alphaToMaskAvailableID = Shader.PropertyToID("_AlphaToMaskAvailable"); + + const string generatePassName = "MOIT Generate Moments Pass"; + const string resolvePassName = "MOIT Resolve Moments Pass"; + const string compositePassName = "MOIT Composite Pass"; + + private static readonly int scaleBiasRt = Shader.PropertyToID("_ScaleBiasRt"); + + + private Settings featureSettings; + private ProfilingSampler profiler; + private CommandBuffer commandBuffer; public MOITPass(Settings settings) { - this.settings = settings; + this.featureSettings = settings; + renderPassEvent = settings.renderPassEvent; + profiler = new(nameof(MOITPass)); + commandBuffer = new CommandBuffer(); + commandBuffer.name = profiler.name; } + public void Dispose() + { + } + + RTHandle moitHandle; + RTHandle b0; + RTHandle b1; + RTHandle b2; + private ShaderTagId shaderTagIdGenerateMoments = new ShaderTagId("GenerateMoments"); + private ShaderTagId shaderTagIdResolveMoments = new ShaderTagId("ResolveMoments"); + + RenderTargetIdentifier[] mrts2 = new RenderTargetIdentifier[2]; + RenderTargetIdentifier[] mrts3 = new RenderTargetIdentifier[3]; + + private const float M_PI = 3.14159265358979323f; + + private static float CircleToParameter(float angle, out float maxParameter) + { + float x = Mathf.Cos(angle); + float y = Mathf.Sin(angle); + float result = Mathf.Abs(y) - Mathf.Abs(x); + result = (x < 0.0f) ? (2.0f - result) : result; + result = (y < 0.0f) ? (6.0f - result) : result; + result += (angle >= 2.0f * M_PI) ? 8.0f : 0.0f; + maxParameter = 7.0f; // why? + return result; + } + + public static Vector4 ComputeWrappingZoneParameters(float newWrappingZoneAngle = 0.1f * M_PI) + { + Vector4 result = new Vector4(); + result.x = newWrappingZoneAngle; + result.y = M_PI - 0.5f * newWrappingZoneAngle; + if (newWrappingZoneAngle <= 0.0f) + { + result.z = 0.0f; + result.w = 0.0f; + } + else + { + float zoneEndParameter; + float zoneBeginParameter = CircleToParameter(2.0f * M_PI - newWrappingZoneAngle, out zoneEndParameter); + result.z = 1.0f / (zoneEndParameter - zoneBeginParameter); + result.w = 1.0f - zoneEndParameter * result.z; + } + return result; + } + + Vector4 wrappingZoneParameters = ComputeWrappingZoneParameters(); + public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { + var biasSettings = featureSettings.biasSettings; + if(biasSettings == null ) + { + return; + } + var settings = featureSettings.settings; + bool isHalfPrecision = settings.momentPrecision == FloatPrecision._Half; + // prevent the use of half precision power moments as quantization relies on ROVs + if (isHalfPrecision && !settings.trigonometric) + isHalfPrecision = false; + + var cmd = commandBuffer; + using var scp = new ProfilingScope(cmd, profiler); + var rdr = renderingData.cameraData.renderer; + ref var cameraData = ref renderingData.cameraData; + RenderTextureDescriptor baseDescriptor = cameraData.cameraTargetDescriptor; + baseDescriptor.colorFormat = RenderTextureFormat.ARGBHalf; + + RenderingUtils.ReAllocateIfNeeded(ref moitHandle, baseDescriptor, name: "_MOIT_Texture"); + + RenderTextureDescriptor descriptorFloat4; + RenderTextureDescriptor descriptorFloat2; + RenderTextureDescriptor descriptorFloat; + if (isHalfPrecision) + { + baseDescriptor.colorFormat = RenderTextureFormat.ARGBHalf; + descriptorFloat4 = baseDescriptor; + baseDescriptor.colorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGHalf) ? RenderTextureFormat.RGHalf : RenderTextureFormat.ARGBHalf; + descriptorFloat2 = baseDescriptor; + baseDescriptor.colorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RHalf) ? RenderTextureFormat.RHalf : RenderTextureFormat.ARGBHalf; + descriptorFloat = baseDescriptor; + } + else // single precision + { + baseDescriptor.colorFormat = RenderTextureFormat.ARGBFloat; + descriptorFloat4 = baseDescriptor; + baseDescriptor.colorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGFloat) ? RenderTextureFormat.RGFloat : RenderTextureFormat.ARGBFloat; + descriptorFloat2 = baseDescriptor; + baseDescriptor.colorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RFloat) ? RenderTextureFormat.RFloat : RenderTextureFormat.ARGBFloat; + descriptorFloat = baseDescriptor; + } + + FilterMode filterMode = FilterMode.Bilinear; + + RenderingUtils.ReAllocateIfNeeded(ref b0, descriptorFloat, name: "_MOIT_B0", filterMode: filterMode); + + RenderingUtils.ReAllocateIfNeeded(ref b1, descriptorFloat4, name: "_MOIT_B1", filterMode: filterMode); + + if (settings.momentsCount == MomentsCount._8) + { + RenderingUtils.ReAllocateIfNeeded(ref b1, descriptorFloat4, name: "_MOIT_B2", filterMode: filterMode); + + } + else if (settings.momentsCount == MomentsCount._6) + { + RenderingUtils.ReAllocateIfNeeded(ref b1, descriptorFloat2, name: "_MOIT_B2", filterMode: filterMode); + } + + SortingCriteria sortingCritera = settings.sortBackToFront ? SortingCriteria.BackToFront | SortingCriteria.OptimizeStateChanges : SortingCriteria.OptimizeStateChanges; + + float momentBias = 0; + Vector2 viewDepthMinMax = Vector2.zero; + if (isHalfPrecision) + { + if (settings.momentsCount == MomentsCount._4) + momentBias = settings.trigonometric ? biasSettings.Trigonometric2Half : biasSettings.Moments4Half; + else if (settings.momentsCount == MomentsCount._6) + momentBias = settings.trigonometric ? biasSettings.Trigonometric3Half : biasSettings.Moments6Half; + else + momentBias = settings.trigonometric ? biasSettings.Trigonometric4Half : biasSettings.Moments8Half; + + } + else + { + if (settings.momentsCount == MomentsCount._4) + momentBias = settings.trigonometric ? biasSettings.Trigonometric2Single : biasSettings.Moments4Single; + else if (settings.momentsCount == MomentsCount._6) + momentBias = settings.trigonometric ? biasSettings.Trigonometric3Single : biasSettings.Moments6Single; + else + momentBias = settings.trigonometric ? biasSettings.Trigonometric4Single : biasSettings.Moments8Single; + } + + DrawingSettings drawSettings = CreateDrawingSettings(shaderTagIdGenerateMoments, ref renderingData, sortingCritera); + + cmd.BeginSample("GenerateMoments"); + mrts2[0] = mrts3[0] = b0; + mrts2[1] = mrts3[1] = b1; + cmd.SetGlobalTexture(b0TextureID, b0); + cmd.SetGlobalTexture(b1TextureID, b1); + if (settings.momentsCount != MomentsCount._4) + { + mrts3[2] = b2; + cmd.SetRenderTarget(mrts3, rdr.cameraDepthTargetHandle); + cmd.SetGlobalTexture(b2TextureID, b2); + } + else + { + cmd.SetRenderTarget(mrts2, rdr.cameraDepthTargetHandle); + } + + var isYFlipped = cameraData.IsRenderTargetProjectionMatrixFlipped(rdr.cameraColorTargetHandle); + float flipSign = isYFlipped ? -1.0f : 1.0f; + // scaleBias.x = flipSign + // scaleBias.y = scale + // scaleBias.z = bias + // scaleBias.w = unused + Vector4 scaleBias = (flipSign < 0.0f) + ? new Vector4(flipSign, 1.0f, -1.0f, 1.0f) + : new Vector4(flipSign, 0.0f, 1.0f, 1.0f); + cmd.SetGlobalVector(scaleBiasRt, scaleBias); + + // setup keywords + CoreUtils.SetKeyword(cmd, "_MOMENT6", settings.momentsCount == MomentsCount._6); + CoreUtils.SetKeyword(cmd, "_MOMENT8", settings.momentsCount == MomentsCount._8); + //CoreUtils.SetKeyword(cmd, "_MOMENT_HALF_PRECISION", data.momentsPrecision == FloatPrecision._Half); + CoreUtils.SetKeyword(cmd, "_MOMENT_HALF_PRECISION", isHalfPrecision); + CoreUtils.SetKeyword(cmd, "_MOMENT_SINGLE_PRECISION", !isHalfPrecision); + CoreUtils.SetKeyword(cmd, "_TRIGONOMETRIC", settings.trigonometric); + + Vector2 logViewDepthMinDelta = new Vector2(Mathf.Log(viewDepthMinMax.x), Mathf.Log(viewDepthMinMax.y)); + logViewDepthMinDelta.y = logViewDepthMinDelta.y - logViewDepthMinDelta.x; + cmd.SetGlobalVector(logViewMinDeltaID, logViewDepthMinDelta); + + if (settings.trigonometric) + { + cmd.SetGlobalVector(wrappingZoneParametersID, wrappingZoneParameters); + } + cmd.SetGlobalFloat(biasID, momentBias); + cmd.SetGlobalFloat(alphaToMaskAvailableID, 0.0f); + cmd.ClearRenderTarget(false, true, Color.clear); + var renderQueue = new RenderQueueRange() + { + lowerBound = settings.renderQueueMin, + upperBound = settings.renderQueueMax + }; + var param = new RendererListParams(renderingData.cullResults, drawSettings, new FilteringSettings(renderQueue, settings.layerMask)); + cmd.DrawRendererList(context.CreateRendererList(ref param)); + cmd.EndSample("GenerateMoments"); + + cmd.BeginSample("ResolveMoments"); + if (settings.debugMakeMOITTexGlobal) + { + cmd.SetGlobalTexture("_MOIT", moitHandle); + } + cmd.SetRenderTarget(moitHandle, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare); + cmd.ClearRenderTarget(false, true, Color.clear); + + drawSettings = CreateDrawingSettings(shaderTagIdResolveMoments, ref renderingData, sortingCritera); + param = new RendererListParams(renderingData.cullResults, drawSettings, new FilteringSettings(renderQueue, settings.layerMask)); + cmd.DrawRendererList(context.CreateRendererList(ref param)); + cmd.EndSample("ResolveMoments"); + + cmd.BeginSample("Composite"); + cmd.Blit(moitHandle, rdr.cameraColorTargetHandle, settings.compositeMaterial, 0); + cmd.EndSample("Composite"); + + context.ExecuteCommandBuffer(cmd); + cmd.Clear(); } } } diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs b/Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs new file mode 100644 index 0000000..181007a --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs @@ -0,0 +1,31 @@ +using System; +using UnityEngine; + +[Serializable] +public class MOITSettings +{ + [Header("Quality features")] + [Tooltip("4 is fine for most situations and the most performant.\nCan be upped to 6 if needed (lots of close objects with varying colors) and still stay somewhat performant\n8 has diminishing returns and trigonometric should be used instead at that point")] + public MOITFeature.MomentsCount momentsCount = MOITFeature.MomentsCount._4; + [Tooltip("Store moments in 16 (half) of 32bit precision (half is fine for most realtime uses)\nUNFORTUNATELY HALF POWER MOMENTS REQUIRE ROVs (Rasterizer Ordered Views) - out of scope for now, so will override to single precision unless trigonometric")] + public MOITFeature.FloatPrecision momentPrecision = MOITFeature.FloatPrecision._Single; //_Half; + [Tooltip("If better precision is needed and performance is not a concern, set trigonometric to true, use single precision and 6 moments (or 8)\n(4 moments = 2 trigonometric, 6m = 3t, 8m = 4t)")] + public bool trigonometric = false; + [Header("Bounds")] + [Tooltip("Method of finding MOIT renderers in order to build the conservative bounding sphere that we use to warp depth, lowering numerical errors\n- NearFarPlanes: just use near and far planes (essentially keep low precision)\n- FindObjects: not optimized but automatic (Renderers only)\n- Register: user needs to add a script to every transparent object (Renderer and VFX)")] + public MOITFeature.BoundsType boundsType = MOITFeature.BoundsType.FindObjects; + [Tooltip("Setting for BoundsType.FindObject and BoundType.Register :\nShould we check if each renderer is visible (by any camera) before adding its bounds?")] + public bool onlyVisibleRenderers = false; + [Header("Rendering")] + [Tooltip("Works with Everything but usually MOIT objects should be set on specific layers that are removed from the Transparent Layer Mask (in Universal Renderer Data) to prevent double rendering")] + public LayerMask layerMask = Physics.AllLayers; + [Tooltip("Set a different RenderQueueRange than default Transparent")] + public int renderQueueMin = 2501; + public int renderQueueMax = 3000; + public Material compositeMaterial; + [Tooltip("Back to front sorting does not matter in OIT techniques so we skip it, however this is probably desirable if you intend to write to depth\n(example : base DoF on the closest transparent object instead of the first opaque on the pixel)")] + public bool sortBackToFront = false; + [Header("Debug")] + [Tooltip("Set this to true to be able to visualize the MOIT texture in the fullscreen feature using RT_test_mat (else only B0 B1 and B2 (if applicable) are available)")] + public bool debugMakeMOITTexGlobal = false; +} diff --git a/Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs.meta b/Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs.meta new file mode 100644 index 0000000..76f2187 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ddbee5a74829c549b5e5b0aeb26ac63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl b/Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl new file mode 100644 index 0000000..189fa16 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl @@ -0,0 +1,395 @@ +#ifndef LIGHTWEIGHT_MOMENT_MATH_INCLUDED +#define LIGHTWEIGHT_MOMENT_MATH_INCLUDED + +/*! Code taken from the blog "Moments in Graphics" by Christoph Peters. + http://momentsingraphics.de/?p=105 + This function computes the three real roots of a cubic polynomial + Coefficient[0]+Coefficient[1]*x+Coefficient[2]*x^2+Coefficient[3]*x^3.*/ +float3 SolveCubic(float4 Coefficient) { + // Normalize the polynomial + Coefficient.xyz /= Coefficient.w; + // Divide middle coefficients by three + Coefficient.yz /= 3.0f; + // Compute the Hessian and the discrimant + float3 Delta = float3( + mad(-Coefficient.z, Coefficient.z, Coefficient.y), + mad(-Coefficient.y, Coefficient.z, Coefficient.x), + dot(float2(Coefficient.z, -Coefficient.y), Coefficient.xy) + ); + float Discriminant = dot(float2(4.0f * Delta.x, -Delta.y), Delta.zy); + // Compute coefficients of the depressed cubic + // (third is zero, fourth is one) + float2 Depressed = float2( + mad(-2.0f * Coefficient.z, Delta.x, Delta.y), + Delta.x + ); + // Take the cubic root of a normalized complex number + float Theta = atan2(sqrt(Discriminant), -Depressed.x) / 3.0f; + float2 CubicRoot; + sincos(Theta, CubicRoot.y, CubicRoot.x); + // Compute the three roots, scale appropriately and + // revert the depression transform + float3 Root = float3( + CubicRoot.x, + dot(float2(-0.5f, -0.5f * sqrt(3.0f)), CubicRoot), + dot(float2(-0.5f, 0.5f * sqrt(3.0f)), CubicRoot) + ); + Root = mad(2.0f * sqrt(-Depressed.y), Root, -Coefficient.z); + return Root; +} +/*! Given coefficients of a quadratic polynomial A*x^2+B*x+C, this function +outputs its two real roots.*/ +float2 solveQuadratic(float3 coeffs) +{ + coeffs[1] *= 0.5; + + float x1, x2, tmp; + + tmp = (coeffs[1] * coeffs[1] - coeffs[0] * coeffs[2]); + if (coeffs[1] >= 0) { + tmp = sqrt(tmp); + x1 = (-coeffs[2]) / (coeffs[1] + tmp); + x2 = (-coeffs[1] - tmp) / coeffs[0]; + } + else { + tmp = sqrt(tmp); + x1 = (-coeffs[1] + tmp) / coeffs[0]; + x2 = coeffs[2] / (-coeffs[1] + tmp); + } + return float2(x1, x2); +} +/*! Given coefficients of a cubic polynomial +coeffs[0]+coeffs[1]*x+coeffs[2]*x^2+coeffs[3]*x^3 with three real roots, +this function returns the root of least magnitude.*/ +float solveCubicBlinnSmallest(float4 coeffs) +{ + coeffs.xyz /= coeffs.w; + coeffs.yz /= 3.0; + + float3 delta = float3(mad(-coeffs.z, coeffs.z, coeffs.y), mad(-coeffs.z, coeffs.y, coeffs.x), coeffs.z * coeffs.x - coeffs.y * coeffs.y); + float discriminant = 4.0 * delta.x * delta.z - delta.y * delta.y; + + float2 depressed = float2(delta.z, -coeffs.x * delta.y + 2.0 * coeffs.y * delta.z); + float theta = abs(atan2(coeffs.x * sqrt(discriminant), -depressed.y)) / 3.0; + float2 sin_cos; + sincos(theta, sin_cos.x, sin_cos.y); + float tmp = 2.0 * sqrt(-depressed.x); + float2 x = float2(tmp * sin_cos.y, tmp * (-0.5 * sin_cos.y - 0.5 * sqrt(3.0) * sin_cos.x)); + float2 s = (x.x + x.y < 2.0 * coeffs.y) ? float2(-coeffs.x, x.x + coeffs.y) : float2(-coeffs.x, x.y + coeffs.y); + + return s.x / s.y; +} +/*! Given coefficients of a quartic polynomial + coeffs[0]+coeffs[1]*x+coeffs[2]*x^2+coeffs[3]*x^3+coeffs[4]*x^4 with four + real roots, this function returns all roots.*/ +float4 solveQuarticNeumark(float coeffs[5]) +{ + // Normalization + float B = coeffs[3] / coeffs[4]; + float C = coeffs[2] / coeffs[4]; + float D = coeffs[1] / coeffs[4]; + float E = coeffs[0] / coeffs[4]; + + // Compute coefficients of the cubic resolvent + float P = -2.0 * C; + float Q = C * C + B * D - 4.0 * E; + float R = D * D + B * B * E - B * C * D; + + // Obtain the smallest cubic root + float y = solveCubicBlinnSmallest(float4(R, Q, P, 1.0)); + + float BB = B * B; + float fy = 4.0 * y; + float BB_fy = BB - fy; + + float Z = C - y; + float ZZ = Z * Z; + float fE = 4.0 * E; + float ZZ_fE = ZZ - fE; + + float G, g, H, h; + // Compute the coefficients of the quadratics adaptively using the two + // proposed factorizations by Neumark. Choose the appropriate + // factorizations using the heuristic proposed by Herbison-Evans. + if (y < 0 || (ZZ + fE) * BB_fy > ZZ_fE * (BB + fy)) { + float tmp = sqrt(BB_fy); + G = (B + tmp) * 0.5; + g = (B - tmp) * 0.5; + + tmp = (B * Z - 2.0 * D) / (2.0 * tmp); + H = mad(Z, 0.5, tmp); + h = mad(Z, 0.5, -tmp); + } + else { + float tmp = sqrt(ZZ_fE); + H = (Z + tmp) * 0.5; + h = (Z - tmp) * 0.5; + + tmp = (B * Z - 2.0 * D) / (2.0 * tmp); + G = mad(B, 0.5, tmp); + g = mad(B, 0.5, -tmp); + } + // Solve the quadratics + return float4(solveQuadratic(float3(1.0, G, H)), solveQuadratic(float3(1.0, g, h))); +} + +/*! This function reconstructs the transmittance at the given depth from four + normalized power moments and the given zeroth moment.*/ +float ComputeTransmittance(float b_0, float2 b_even, float2 b_odd, float depth, float bias, float overestimation, float4 bias_vector) +{ + float4 b = float4(b_odd.x, b_even.x, b_odd.y, b_even.y); + // Bias input data to avoid artifacts + b = lerp(b, bias_vector, bias); + float3 z; + z[0] = depth; + + // Compute a Cholesky factorization of the Hankel matrix B storing only non- + // trivial entries or related products + float L21D11 = mad(-b[0], b[1], b[2]); + float D11 = mad(-b[0], b[0], b[1]); + float InvD11 = 1.0f / D11; + float L21 = L21D11 * InvD11; + float SquaredDepthVariance = mad(-b[1], b[1], b[3]); + float D22 = mad(-L21D11, L21, SquaredDepthVariance); + + // Obtain a scaled inverse image of bz=(1,z[0],z[0]*z[0])^T + float3 c = float3(1.0f, z[0], z[0] * z[0]); + // Forward substitution to solve L*c1=bz + c[1] -= b.x; + c[2] -= b.y + L21 * c[1]; + // Scaling to solve D*c2=c1 + c[1] *= InvD11; + c[2] /= D22; + // Backward substitution to solve L^T*c3=c2 + c[1] -= L21 * c[2]; + c[0] -= dot(c.yz, b.xy); + // Solve the quadratic equation c[0]+c[1]*z+c[2]*z^2 to obtain solutions + // z[1] and z[2] + float InvC2 = 1.0f / c[2]; + float p = c[1] * InvC2; + float q = c[0] * InvC2; + float D = (p * p * 0.25f) - q; + float r = sqrt(D); + z[1] = -p * 0.5f - r; + z[2] = -p * 0.5f + r; + // Compute the absorbance by summing the appropriate weights + float3 polynomial; + float3 weight_factor = float3(overestimation, (z[1] < z[0]) ? 1.0f : 0.0f, (z[2] < z[0]) ? 1.0f : 0.0f); + float f0 = weight_factor[0]; + float f1 = weight_factor[1]; + float f2 = weight_factor[2]; + float f01 = (f1 - f0) / (z[1] - z[0]); + float f12 = (f2 - f1) / (z[2] - z[1]); + float f012 = (f12 - f01) / (z[2] - z[0]); + polynomial[0] = f012; + polynomial[1] = polynomial[0]; + polynomial[0] = f01 - polynomial[0] * z[1]; + polynomial[2] = polynomial[1]; + polynomial[1] = polynomial[0] - polynomial[1] * z[0]; + polynomial[0] = f0 - polynomial[0] * z[0]; + float absorbance = polynomial[0] + dot(b.xy, polynomial.yz);; + // Turn the normalized absorbance into transmittance + return saturate(exp(-b_0 * absorbance)); +} +/*! This function reconstructs the transmittance at the given depth from six + normalized power moments and the given zeroth moment.*/ +float ComputeTransmittance(float b_0, float3 b_even, float3 b_odd, float depth, float bias, float overestimation, float bias_vector[6]) +{ + float b[6] = { b_odd.x, b_even.x, b_odd.y, b_even.y, b_odd.z, b_even.z }; + // Bias input data to avoid artifacts + //[unroll] + UNITY_UNROLL + for (int i = 0; i != 6; ++i) { + b[i] = lerp(b[i], bias_vector[i], bias); + } + + float4 z; + z[0] = depth; + + // Compute a Cholesky factorization of the Hankel matrix B storing only non- + // trivial entries or related products + float InvD11 = 1.0f / mad(-b[0], b[0], b[1]); + float L21D11 = mad(-b[0], b[1], b[2]); + float L21 = L21D11 * InvD11; + float D22 = mad(-L21D11, L21, mad(-b[1], b[1], b[3])); + float L31D11 = mad(-b[0], b[2], b[3]); + float L31 = L31D11 * InvD11; + float InvD22 = 1.0f / D22; + float L32D22 = mad(-L21D11, L31, mad(-b[1], b[2], b[4])); + float L32 = L32D22 * InvD22; + float D33 = mad(-b[2], b[2], b[5]) - dot(float2(L31D11, L32D22), float2(L31, L32)); + float InvD33 = 1.0f / D33; + + // Construct the polynomial whose roots have to be points of support of the + // canonical distribution: bz=(1,z[0],z[0]*z[0],z[0]*z[0]*z[0])^T + float4 c; + c[0] = 1.0f; + c[1] = z[0]; + c[2] = c[1] * z[0]; + c[3] = c[2] * z[0]; + // Forward substitution to solve L*c1=bz + c[1] -= b[0]; + c[2] -= mad(L21, c[1], b[1]); + c[3] -= b[2] + dot(float2(L31, L32), c.yz); + // Scaling to solve D*c2=c1 + c.yzw *= float3(InvD11, InvD22, InvD33); + // Backward substitution to solve L^T*c3=c2 + c[2] -= L32 * c[3]; + c[1] -= dot(float2(L21, L31), c.zw); + c[0] -= dot(float3(b[0], b[1], b[2]), c.yzw); + + // Solve the cubic equation + z.yzw = SolveCubic(c); + + // Compute the absorbance by summing the appropriate weights + float4 weigth_factor; + weigth_factor[0] = overestimation; + weigth_factor.yzw = (z.yzw > z.xxx) ? float3 (0.0f, 0.0f, 0.0f) : float3 (1.0f, 1.0f, 1.0f); + // Construct an interpolation polynomial + float f0 = weigth_factor[0]; + float f1 = weigth_factor[1]; + float f2 = weigth_factor[2]; + float f3 = weigth_factor[3]; + float f01 = (f1 - f0) / (z[1] - z[0]); + float f12 = (f2 - f1) / (z[2] - z[1]); + float f23 = (f3 - f2) / (z[3] - z[2]); + float f012 = (f12 - f01) / (z[2] - z[0]); + float f123 = (f23 - f12) / (z[3] - z[1]); + float f0123 = (f123 - f012) / (z[3] - z[0]); + float4 polynomial; + // f012+f0123 *(z-z2) + polynomial[0] = mad(-f0123, z[2], f012); + polynomial[1] = f0123; + // *(z-z1) +f01 + polynomial[2] = polynomial[1]; + polynomial[1] = mad(polynomial[1], -z[1], polynomial[0]); + polynomial[0] = mad(polynomial[0], -z[1], f01); + // *(z-z0) +f0 + polynomial[3] = polynomial[2]; + polynomial[2] = mad(polynomial[2], -z[0], polynomial[1]); + polynomial[1] = mad(polynomial[1], -z[0], polynomial[0]); + polynomial[0] = mad(polynomial[0], -z[0], f0); + float absorbance = dot(polynomial, float4 (1.0, b[0], b[1], b[2])); + // Turn the normalized absorbance into transmittance + return saturate(exp(-b_0 * absorbance)); +} + +float ComputeTransmittance(float b_0, float4 b_even, float4 b_odd, float depth, float bias, float overestimation, float bias_vector[8]) +{ + float b[8] = { b_odd.x, b_even.x, b_odd.y, b_even.y, b_odd.z, b_even.z, b_odd.w, b_even.w }; + // Bias input data to avoid artifacts + //[unroll] + UNITY_UNROLL + for (int i = 0; i != 8; ++i) { + b[i] = lerp(b[i], bias_vector[i], bias); + } + + float z[5]; + z[0] = depth; + + // Compute a Cholesky factorization of the Hankel matrix B storing only non-trivial entries or related products + float D22 = mad(-b[0], b[0], b[1]); + float InvD22 = 1.0 / D22; + float L32D22 = mad(-b[1], b[0], b[2]); + float L32 = L32D22 * InvD22; + float L42D22 = mad(-b[2], b[0], b[3]); + float L42 = L42D22 * InvD22; + float L52D22 = mad(-b[3], b[0], b[4]); + float L52 = L52D22 * InvD22; + + float D33 = mad(-L32, L32D22, mad(-b[1], b[1], b[3])); + float InvD33 = 1.0 / D33; + float L43D33 = mad(-L42, L32D22, mad(-b[2], b[1], b[4])); + float L43 = L43D33 * InvD33; + float L53D33 = mad(-L52, L32D22, mad(-b[3], b[1], b[5])); + float L53 = L53D33 * InvD33; + + float D44 = mad(-b[2], b[2], b[5]) - dot(float2(L42, L43), float2(L42D22, L43D33)); + float InvD44 = 1.0 / D44; + float L54D44 = mad(-b[3], b[2], b[6]) - dot(float2(L52, L53), float2(L42D22, L43D33)); + float L54 = L54D44 * InvD44; + + float D55 = mad(-b[3], b[3], b[7]) - dot(float3(L52, L53, L54), float3(L52D22, L53D33, L54D44)); + float InvD55 = 1.0 / D55; + + // Construct the polynomial whose roots have to be points of support of the + // Canonical distribution: + // bz = (1,z[0],z[0]^2,z[0]^3,z[0]^4)^T + float c[5]; + c[0] = 1.0; + c[1] = z[0]; + c[2] = c[1] * z[0]; + c[3] = c[2] * z[0]; + c[4] = c[3] * z[0]; + + // Forward substitution to solve L*c1 = bz + c[1] -= b[0]; + c[2] -= mad(L32, c[1], b[1]); + c[3] -= b[2] + dot(float2(L42, L43), float2(c[1], c[2])); + c[4] -= b[3] + dot(float3(L52, L53, L54), float3(c[1], c[2], c[3])); + + // Scaling to solve D*c2 = c1 + //c = c .*[1, InvD22, InvD33, InvD44, InvD55]; + c[1] *= InvD22; + c[2] *= InvD33; + c[3] *= InvD44; + c[4] *= InvD55; + + // Backward substitution to solve L^T*c3 = c2 + c[3] -= L54 * c[4]; + c[2] -= dot(float2(L53, L43), float2(c[4], c[3])); + c[1] -= dot(float3(L52, L42, L32), float3(c[4], c[3], c[2])); + c[0] -= dot(float4(b[3], b[2], b[1], b[0]), float4(c[4], c[3], c[2], c[1])); + + // Solve the quartic equation + float4 zz = solveQuarticNeumark(c); + z[1] = zz[0]; + z[2] = zz[1]; + z[3] = zz[2]; + z[4] = zz[3]; + + // Compute the absorbance by summing the appropriate weights + float4 weigth_factor = (float4(z[1], z[2], z[3], z[4]) <= z[0].xxxx); + // Construct an interpolation polynomial + float f0 = overestimation; + float f1 = weigth_factor[0]; + float f2 = weigth_factor[1]; + float f3 = weigth_factor[2]; + float f4 = weigth_factor[3]; + float f01 = (f1 - f0) / (z[1] - z[0]); + float f12 = (f2 - f1) / (z[2] - z[1]); + float f23 = (f3 - f2) / (z[3] - z[2]); + float f34 = (f4 - f3) / (z[4] - z[3]); + float f012 = (f12 - f01) / (z[2] - z[0]); + float f123 = (f23 - f12) / (z[3] - z[1]); + float f234 = (f34 - f23) / (z[4] - z[2]); + float f0123 = (f123 - f012) / (z[3] - z[0]); + float f1234 = (f234 - f123) / (z[4] - z[1]); + float f01234 = (f1234 - f0123) / (z[4] - z[0]); + + float Polynomial_0; + float4 Polynomial; + // f0123 + f01234 * (z - z3) + Polynomial_0 = mad(-f01234, z[3], f0123); + Polynomial[0] = f01234; + // * (z - z2) + f012 + Polynomial[1] = Polynomial[0]; + Polynomial[0] = mad(-Polynomial[0], z[2], Polynomial_0); + Polynomial_0 = mad(-Polynomial_0, z[2], f012); + // * (z - z1) + f01 + Polynomial[2] = Polynomial[1]; + Polynomial[1] = mad(-Polynomial[1], z[1], Polynomial[0]); + Polynomial[0] = mad(-Polynomial[0], z[1], Polynomial_0); + Polynomial_0 = mad(-Polynomial_0, z[1], f01); + // * (z - z0) + f1 + Polynomial[3] = Polynomial[2]; + Polynomial[2] = mad(-Polynomial[2], z[0], Polynomial[1]); + Polynomial[1] = mad(-Polynomial[1], z[0], Polynomial[0]); + Polynomial[0] = mad(-Polynomial[0], z[0], Polynomial_0); + Polynomial_0 = mad(-Polynomial_0, z[0], f0); + float absorbance = Polynomial_0 + dot(Polynomial, float4(b[0], b[1], b[2], b[3])); + // Turn the normalized absorbance into transmittance + return saturate(exp(-b_0 * absorbance)); +} +// replace [unroll] with UNITY_UNROLL for metal etc compatibility +#endif \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl.meta new file mode 100644 index 0000000..519f999 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 01ecfba35fc1e0743acd03dfde076125 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl b/Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl new file mode 100644 index 0000000..ad27f24 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl @@ -0,0 +1,20 @@ +#if _MOMENT_HALF_PRECISION + #define f1 half + #define f2 half2 + #define f4 half4 +#else // _MOMENT_SINGLE_PRECISION + #define f1 float + #define f2 float2 + #define f4 float4 +#endif + +struct MomentOutput +{ + f1 b0 : SV_Target0; + f4 b1 : SV_Target1; +#ifdef _MOMENT8 + f4 b2 : SV_Target2; +#elif defined(_MOMENT6) + f2 b2 : SV_Target2; +#endif +}; \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl.meta new file mode 100644 index 0000000..85b66df --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b726e2096ac821a4696aa328564a4e3c +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl b/Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl new file mode 100644 index 0000000..17a1dbf --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl @@ -0,0 +1,98 @@ +// we use this to prevent artifacts with half (16bit) moments +// this is only for power moments as trigonometric moments do not suffer as much from rounding errors (quote from the guys who actually did this technique) +// see https://momentsingraphics.de/I3D2018.html + +// Definition of utility functions for quantization and dequantization of power moments stored in 16 bits per moment + +// NOTE : It seems that ROVs are necessary for this to work, unfortunately this is out of scope for now + +// 4 MOMENTS +void offsetMoments(inout float2 b_even, inout float2 b_odd, float sign) +{ + b_odd += 0.5 * sign; +} + +void quantizeMoments(out float2 b_even_q, out float2 b_odd_q, float2 b_even, float2 b_odd) +{ + b_odd_q = mul(b_odd, float2x2(1.5f, sqrt(3.0f) * 0.5f, -2.0f, -sqrt(3.0f) * 2.0f / 9.0f)); + b_even_q = mul(b_even, float2x2(4.0f, 0.5f, -4.0f, 0.5f)); +} + +void offsetAndDequantizeMoments(out float2 b_even, out float2 b_odd, float2 b_even_q, float2 b_odd_q) +{ + offsetMoments(b_even_q, b_odd_q, -1.0); + b_odd = mul(b_odd_q, float2x2(-1.0f / 3.0f, -0.75f, sqrt(3.0f), 0.75f * sqrt(3.0f))); + b_even = mul(b_even_q, float2x2(0.125f, -0.125f, 1.0f, 1.0f)); +} + +// 6 MOMENTS +void offsetMoments(inout float3 b_even, inout float3 b_odd, float sign) +{ + b_odd += 0.5 * sign; + b_even.z += 0.018888946f * sign; +} + +void quantizeMoments(out float3 b_even_q, out float3 b_odd_q, float3 b_even, float3 b_odd) +{ + const float3x3 QuantizationMatrixOdd = float3x3( + 2.5f, -1.87499864450f, 1.26583039016f, + -10.0f, 4.20757543111f, -1.47644882902f, + 8.0f, -1.83257678661f, 0.71061660238f); + const float3x3 QuantizationMatrixEven = float3x3( + 4.0f, 9.0f, -0.57759806484f, + -4.0f, -24.0f, 4.61936647543f, + 0.0f, 16.0f, -3.07953906655f); + b_odd_q = mul(b_odd, QuantizationMatrixOdd); + b_even_q = mul(b_even, QuantizationMatrixEven); +} + +void offsetAndDequantizeMoments(out float3 b_even, out float3 b_odd, float3 b_even_q, float3 b_odd_q) +{ + const float3x3 QuantizationMatrixOdd = float3x3( + -0.02877789192f, 0.09995235706f, 0.25893353755f, + 0.47635550422f, 0.84532580931f, 0.90779616657f, + 1.55242808973f, 1.05472570761f, 0.83327335647f); + const float3x3 QuantizationMatrixEven = float3x3( + 0.00001253044f, -0.24998746956f, -0.37498825271f, + 0.16668494186f, 0.16668494186f, 0.21876713299f, + 0.86602540579f, 0.86602540579f, 0.81189881793f); + offsetMoments(b_even_q, b_odd_q, -1.0); + b_odd = mul(b_odd_q, QuantizationMatrixOdd); + b_even = mul(b_even_q, QuantizationMatrixEven); +} + +// 8 MOMENTS +void offsetMoments(inout float4 b_even, inout float4 b_odd, float sign) +{ + b_odd += 0.5 * sign; + b_even += float4(0.972481993925964, 1.0, 0.999179192513328, 0.991778293073131) * sign; +} + +void quantizeMoments(out float4 b_even_q, out float4 b_odd_q, float4 b_even, float4 b_odd) +{ + const float4x4 mat_odd = float4x4(3.48044635732474, -27.5760737514826, 55.1267384344761, -31.5311110403183, + 1.26797185782836, -0.928755808743913, -2.07520453231032, 1.23598848322588, + -2.1671560004294, 6.17950199592966, -0.276515571579297, -4.23583042392097, + 0.974332879165755, -0.443426830933027, -0.360491648368785, 0.310149466050223); + const float4x4 mat_even = float4x4(0.280504133158527, -0.757633844606942, 0.392179589334688, -0.887531871812237, + -2.01362265883247, 0.221551373038988, -1.06107954265125, 2.83887201588367, + -7.31010494985321, 13.9855979699139, -0.114305766176437, -7.4361899359832, + -15.8954215629556, 79.6186327084103, -127.457278992502, 63.7349456687829); + b_odd_q = mul(mat_odd, b_odd); + b_even_q = mul(mat_even, b_even); +} + +void offsetAndDequantizeMoments(out float4 b_even, out float4 b_odd, float4 b_even_q, float4 b_odd_q) +{ + const float4x4 mat_odd = float4x4(-0.00482399708502382, -0.423201508674231, 0.0348312382605129, 1.67179208266592, + -0.0233402218644408, -0.832829097046478, 0.0193406040499625, 1.21021509068975, + -0.010888537031885, -0.926393772997063, -0.11723394414779, 0.983723301818275, + -0.0308713357806732, -0.937989172670245, -0.218033377677099, 0.845991731322996); + const float4x4 mat_even = float4x4(-0.976220278891035, -0.456139260269401, -0.0504335521016742, 0.000838800390651085, + -1.04828341778299, -0.229726640510149, 0.0259608334616091, -0.00133632693205861, + -1.03115268628604, -0.077844420809897, 0.00443408851014257, -0.0103744938457406, + -0.996038443434636, 0.0175438624416783, -0.0361414253243963, -0.00317839994022725); + offsetMoments(b_even_q, b_odd_q, -1.0); + b_odd = mul(mat_odd, b_odd_q); + b_even = mul(mat_even, b_even_q); +} \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl.meta new file mode 100644 index 0000000..f9c976a --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 280699927ed265b4a8641989996cdec3 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl b/Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl new file mode 100644 index 0000000..6caa91d --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl @@ -0,0 +1,131 @@ +#ifdef _MOMENT_SINGLE_PRECISION +TEXTURE2D_X_FLOAT(_B0); +TEXTURE2D_X_FLOAT(_B1); + +#if defined(_MOMENT8) || defined(_MOMENT6) +TEXTURE2D_X_FLOAT(_B2); +#endif +#else +TEXTURE2D_X_HALF(_B0); +TEXTURE2D_X_HALF(_B1); + +#if defined(_MOMENT8) || defined(_MOMENT6) +TEXTURE2D_X_HALF(_B2); +#endif +#endif + +float4 _B0_TexelSize; +float _MOIT_MomentBias; +//float _MomentBias; // switched to global +float _Overestimation = 0.25f; // overestimation can be declared properties in the shader, but the 0.25f default is the recommended value in the paper +float4 _WrappingZoneParameters; + +// sampler_PointClamp sampler_LinearClamp +#define singleSampler sampler_LinearClamp +#define sampler_B0 singleSampler +#define sampler_B1 singleSampler +#if defined(_MOMENT8) || defined(_MOMENT6) + #define sampler_B2 singleSampler +#endif + +// TODO: check if can use LOAD_FRAMEBUFFER_X_INPUT(index, positionCS.xy); (float2 p = positionCS.xy) + +void ResolveMoments(out float td, out float tt, float vd, float2 p) +{ + float d = WarpDepth(vd); + td = 1; + tt = 1; + float b0 = SAMPLE_TEXTURE2D_X(_B0, sampler_B0, p).r; + + // Return early if the surface is fully transparent + clip(b0 - 0.00100050033f); + + tt = exp(-b0); + + float4 b1 = SAMPLE_TEXTURE2D_X(_B1, sampler_B1, p); + //b1 /= b0; // had to move as quantized does things different +#ifdef _MOMENT8 + float4 b2 = SAMPLE_TEXTURE2D_X(_B2, sampler_B2, p); + //b2 /= b0; +#ifdef _TRIGONOMETRIC + b1 /= b0; + b2 /= b0; + float2 tb[4]; + tb[0] = b1.xy; + tb[1] = b1.zw; + tb[2] = b2.xy; + tb[3] = b2.zw; + td = ComputeTransmittanceTrigonometric(b0, tb, d, _MOIT_MomentBias, _Overestimation, _WrappingZoneParameters); +#else // 8 POWER MOMENTS +#if _MOMENT_SINGLE_PRECISION + b1 /= b0; + b2 /= b0; + float4 be = float4(b1.yw, b2.yw); + float4 bo = float4(b1.xz, b2.xz); + + const float bias[8] = { 0, 0.75, 0, 0.67666666666666664, 0, 0.64, 0, 0.60030303030303034 }; + //td = ComputeTransmittance(b0, be, bo, d, _MOIT_MomentBias, _Overestimation, bias); +#else // HALF (DEQUANTIZE) + float4 beq = float4(b1.yw, b2.yw); + float4 boq = float4(b1.xz, b2.xz); + float4 be, bo; + offsetAndDequantizeMoments(be, bo, beq, boq); + const float bias[8] = { 0, 0.42474916387959866, 0, 0.22407802675585284, 0, 0.15369230769230768, 0, 0.12900440529089119 }; +#endif + td = ComputeTransmittance(b0, be, bo, d, _MOIT_MomentBias, _Overestimation, bias); +#endif +#elif defined(_MOMENT6) + float2 b2 = SAMPLE_TEXTURE2D_X(_B2, sampler_B2, p).rg; + //b2 /= b0; +#ifdef _TRIGONOMETRIC + b1 /= b0; + b2 /= b0; + float2 tb[3]; + tb[0] = b1.xy; + tb[1] = b1.zw; + tb[2] = b2.xy; + td = ComputeTransmittanceTrigonometric(b0, tb, d, _MOIT_MomentBias, _Overestimation, _WrappingZoneParameters); +#else // 6 POWER MOMENTS +#if _MOMENT_SINGLE_PRECISION + b1 /= b0; + b2 /= b0; + float3 be = float3(b1.yw, b2.y); + float3 bo = float3(b1.xz, b2.x); + + const float bias[6] = { 0, 0.48, 0, 0.451, 0, 0.45 }; + //td = ComputeTransmittance(b0, be, bo, d, _MOIT_MomentBias, _Overestimation, bias); +#else // DEQUANTIZE + float3 beq = float3(b1.yw, b2.y); + float3 boq = float3(b1.xz, b2.x); + float3 be, bo; + offsetAndDequantizeMoments(be, bo, beq, boq); + const float bias[6] = { 0, 0.5566, 0, 0.489, 0, 0.47869382 }; +#endif + td = ComputeTransmittance(b0, be, bo, d, _MOIT_MomentBias, _Overestimation, bias); +#endif +#else // _MOMENT4 +#ifdef _TRIGONOMETRIC + b1 /= b0; + float2 tb[2]; + tb[0] = b1.xy; + tb[1] = b1.zw; + td = ComputeTransmittanceTrigonometric(b0, tb, d, _MOIT_MomentBias, _Overestimation, _WrappingZoneParameters); +#else // 4 POWER MOMENTS +#if _MOMENT_SINGLE_PRECISION + b1 /= b0; + float2 be = b1.yw; + float2 bo = b1.xz; + + const float4 bias = float4 (0, 0.375, 0, 0.375); + //td = ComputeTransmittance(b0, be, bo, d, _MOIT_MomentBias, _Overestimation, bias); +#else // QUANTIZED + float2 beq = b1.yw; + float2 boq = b1.xz; + float2 be, bo; + offsetAndDequantizeMoments(be, bo, beq, boq); + const float4 bias = float4(0, 0.628, 0, 0.628); +#endif + td = ComputeTransmittance(b0, be, bo, d, _MOIT_MomentBias, _Overestimation, bias); +#endif +#endif +} \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl.meta new file mode 100644 index 0000000..4f0f685 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3ebfeb4e0588c2e4c9740481884ec4b5 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl b/Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl new file mode 100644 index 0000000..6018fdf --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl @@ -0,0 +1,510 @@ +#ifndef LIGHTWEIGHT_TRIGONOMETRIC_MOMENT_MATH_INCLUDED +#define LIGHTWEIGHT_TRIGONOMETRIC_MOMENT_MATH_INCLUDED + +/*! Returns the complex conjugate of the given complex number (i.e. it changes + the sign of the y-component).*/ +float2 Conjugate(float2 Z) { + return float2(Z.x, -Z.y); +} +/*! This function implements complex multiplication.*/ +float2 Multiply(float2 LHS, float2 RHS) { + return float2(LHS.x * RHS.x - LHS.y * RHS.y, LHS.x * RHS.y + LHS.y * RHS.x); +} +/*! This function computes the magnitude of the given complex number.*/ +float Magnitude(float2 Z) { + return sqrt(dot(Z, Z)); +} +/*! This function computes the quotient of two complex numbers. The denominator + must not be zero.*/ +float2 Divide(float2 Numerator, float2 Denominator) { + return float2(Numerator.x * Denominator.x + Numerator.y * Denominator.y, -Numerator.x * Denominator.y + Numerator.y * Denominator.x) / dot(Denominator, Denominator); +} +/*! This function divides a real number by a complex number. The denominator + must not be zero.*/ +float2 Divide(float Numerator, float2 Denominator) { + return float2(Numerator * Denominator.x, -Numerator * Denominator.y) / dot(Denominator, Denominator); +} +/*! This function implements computation of the reciprocal of the given non- + zero complex number.*/ +float2 Reciprocal(float2 Z) { + return float2(Z.x, -Z.y) / dot(Z, Z); +} +/*! This utility function implements complex squaring.*/ +float2 Square(float2 Z) { + return float2(Z.x * Z.x - Z.y * Z.y, 2.0f * Z.x * Z.y); +} +/*! This utility function implements complex computation of the third power.*/ +float2 Cube(float2 Z) { + return Multiply(Square(Z), Z); +} +/*! This utility function computes one square root of the given complex value. + The other one can be found using the unary minus operator. + \warning This function is continuous but not defined on the negative real + axis (and cannot be continued continuously there). + \sa SquareRoot() */ +float2 SquareRootUnsafe(float2 Z) { + float ZLengthSq = dot(Z, Z); + float ZLengthInv = rsqrt(ZLengthSq); + float2 UnnormalizedRoot = Z * ZLengthInv + float2(1.0f, 0.0f); + float UnnormalizedRootLengthSq = dot(UnnormalizedRoot, UnnormalizedRoot); + float NormalizationFactorInvSq = UnnormalizedRootLengthSq * ZLengthInv; + float NormalizationFactor = rsqrt(NormalizationFactorInvSq); + return NormalizationFactor * UnnormalizedRoot; +} +/*! This utility function computes one square root of the given complex value. + The other one can be found using the unary minus operator. + \note This function has discontinuities for values with real part zero. + \sa SquareRootUnsafe() */ +float2 SquareRoot(float2 Z) { + float2 ZPositiveRealPart = float2(abs(Z.x), Z.y); + float2 ComputedRoot = SquareRootUnsafe(ZPositiveRealPart); + return (Z.x >= 0.0) ? ComputedRoot : ComputedRoot.yx; +} +/*! This utility function computes one cubic root of the given complex value. The + other roots can be found by multiplication by cubic roots of unity. + \note This function has various discontinuities.*/ +float2 CubicRoot(float2 Z) { + float Argument = atan2(Z.y, Z.x); + float NewArgument = Argument / 3.0f; + float2 NormalizedRoot; + sincos(NewArgument, NormalizedRoot.y, NormalizedRoot.x); + return NormalizedRoot * pow(dot(Z, Z), 1.0f / 6.0f); +} + +/*! @{ + Returns the complex conjugate of the given complex vector (i.e. it changes the + second column resp the y-component).*/ +float2x2 Conjugate(float2x2 Vector) { + return float2x2(Vector[0].x, -Vector[0].y, Vector[1].x, -Vector[1].y); +} +float3x2 Conjugate(float3x2 Vector) { + return float3x2(Vector[0].x, -Vector[0].y, Vector[1].x, -Vector[1].y, Vector[2].x, -Vector[2].y); +} +float4x2 Conjugate(float4x2 Vector) { + return float4x2(Vector[0].x, -Vector[0].y, Vector[1].x, -Vector[1].y, Vector[2].x, -Vector[2].y, Vector[3].x, -Vector[3].y); +} +void Conjugate(out float2 OutConjugateVector[5], float2 Vector[5]) { + [unroll] for (int i = 0; i != 5; ++i) { + OutConjugateVector[i] = float2(Vector[i].x, -Vector[i].x); + } +} +//!@} + +/*! Returns the real part of a complex number as real.*/ +float RealPart(float2 Z) { + return Z.x; +} + +/*! Given coefficients of a quadratic polynomial A*x^2+B*x+C, this function + outputs its two complex roots.*/ +void SolveQuadratic(out float2 pOutRoot[2], float2 A, float2 B, float2 C) +{ + // Normalize the coefficients + float2 InvA = Reciprocal(A); + B = Multiply(B, InvA); + C = Multiply(C, InvA); + // Divide the middle coefficient by two + B *= 0.5f; + // Apply the quadratic formula + float2 DiscriminantRoot = SquareRoot(Square(B) - C); + pOutRoot[0] = -B - DiscriminantRoot; + pOutRoot[1] = -B + DiscriminantRoot; +} + +/*! Given coefficients of a cubic polynomial A*x^3+B*x^2+C*x+D, this function + outputs its three complex roots.*/ +void SolveCubicBlinn(out float2 pOutRoot[3], float2 A, float2 B, float2 C, float2 D) +{ + // Normalize the polynomial + float2 InvA = Reciprocal(A); + B = Multiply(B, InvA); + C = Multiply(C, InvA); + D = Multiply(D, InvA); + // Divide middle coefficients by three + B /= 3.0f; + C /= 3.0f; + // Compute the Hessian and the discriminant + float2 Delta00 = -Square(B) + C; + float2 Delta01 = -Multiply(C, B) + D; + float2 Delta11 = Multiply(B, D) - Square(C); + float2 Discriminant = 4.0f * Multiply(Delta00, Delta11) - Square(Delta01); + // Compute coefficients of the depressed cubic + // (third is zero, fourth is one) + float2 DepressedD = -2.0f * Multiply(B, Delta00) + Delta01; + float2 DepressedC = Delta00; + // Take the cubic root of a complex number avoiding cancellation + float2 DiscriminantRoot = SquareRoot(-Discriminant); + DiscriminantRoot = faceforward(DiscriminantRoot, DiscriminantRoot, DepressedD); + float2 CubedRoot = DiscriminantRoot - DepressedD; + float2 FirstRoot = CubicRoot(0.5f * CubedRoot); + float2 pCubicRoot[3] = { + FirstRoot, + Multiply(float2(-0.5f,-0.5f * sqrt(3.0f)),FirstRoot), + Multiply(float2(-0.5f, 0.5f * sqrt(3.0f)),FirstRoot) + }; + // Also compute the reciprocal cubic roots + float2 InvFirstRoot = Reciprocal(FirstRoot); + float2 pInvCubicRoot[3] = { + InvFirstRoot, + Multiply(float2(-0.5f, 0.5f * sqrt(3.0f)),InvFirstRoot), + Multiply(float2(-0.5f,-0.5f * sqrt(3.0f)),InvFirstRoot) + }; + // Turn them into roots of the depressed cubic and revert the depression + // transform + [unroll] + for (int i = 0; i != 3; ++i) + { + pOutRoot[i] = pCubicRoot[i] - Multiply(DepressedC, pInvCubicRoot[i]) - B; + } +} + + +/*! Given coefficients of a quartic polynomial A*x^4+B*x^3+C*x^2+D*x+E, this + function outputs its four complex roots.*/ +void SolveQuarticNeumark(out float2 pOutRoot[4], float2 A, float2 B, float2 C, float2 D, float2 E) +{ + // Normalize the polynomial + float2 InvA = Reciprocal(A); + B = Multiply(B, InvA); + C = Multiply(C, InvA); + D = Multiply(D, InvA); + E = Multiply(E, InvA); + // Construct a normalized cubic + float2 P = -2.0f * C; + float2 Q = Square(C) + Multiply(B, D) - 4.0f * E; + float2 R = Square(D) + Multiply(Square(B), E) - Multiply(Multiply(B, C), D); + // Compute a root that is not the smallest of the cubic + float2 pCubicRoot[3]; + SolveCubicBlinn(pCubicRoot, float2(1.0f, 0.0f), P, Q, R); + float2 y = (dot(pCubicRoot[1], pCubicRoot[1]) > dot(pCubicRoot[0], pCubicRoot[0])) ? pCubicRoot[1] : pCubicRoot[0]; + + // Solve a quadratic to obtain linear coefficients for quadratic polynomials + float2 BB = Square(B); + float2 fy = 4.0f * y; + float2 BB_fy = BB - fy; + float2 tmp = SquareRoot(BB_fy); + float2 G = (B + tmp) * 0.5f; + float2 g = (B - tmp) * 0.5f; + // Construct the corresponding constant coefficients + float2 Z = C - y; + tmp = Divide(0.5f * Multiply(B, Z) - D, tmp); + float2 H = Z * 0.5f + tmp; + float2 h = Z * 0.5f - tmp; + + // Compute the roots + float2 pQuadraticRoot[2]; + SolveQuadratic(pQuadraticRoot, float2(1.0f, 0.0f), G, H); + pOutRoot[0] = pQuadraticRoot[0]; + pOutRoot[1] = pQuadraticRoot[1]; + SolveQuadratic(pQuadraticRoot, float2(1.0f, 0.0f), g, h); + pOutRoot[2] = pQuadraticRoot[0]; + pOutRoot[3] = pQuadraticRoot[1]; +} + +/*! This utility function turns a point on the unit circle into a scalar + parameter. It is guaranteed to grow monotonically for (cos(phi),sin(phi)) + with phi in 0 to 2*pi. There are no other guarantees. In particular it is + not an arclength parametrization. If you change this function, you must + also change circleToParameter() in MomentOIT.cpp.*/ +float circleToParameter(float2 circle_point) { + float result = abs(circle_point.y) - abs(circle_point.x); + result = (circle_point.x < 0.0f) ? (2.0f - result) : result; + return (circle_point.y < 0.0f) ? (6.0f - result) : result; +} + +/*! This utility function returns the appropriate weight factor for a root at + the given location. Both inputs are supposed to be unit vectors. If a + circular arc going counter clockwise from (1.0,0.0) meets root first, it + returns 1.0, otherwise 0.0 or a linear ramp in the wrapping zone.*/ +float getRootWeightFactor(float reference_parameter, float root_parameter, float4 wrapping_zone_parameters) { + float binary_weight_factor = (root_parameter < reference_parameter) ? 1.0f : 0.0f; + float linear_weight_factor = saturate(mad(root_parameter, wrapping_zone_parameters.z, wrapping_zone_parameters.w)); + return binary_weight_factor + linear_weight_factor; +} + +/*! This function reconstructs the transmittance at the given depth from two + normalized trigonometric moments.*/ +float ComputeTransmittanceTrigonometric(float b_0, float2 trig_b[2], float depth, float bias, float overestimation, float4 wrapping_zone_parameters) +{ + // Apply biasing and reformat the inputs a little bit + float moment_scale = 1.0f - bias; + float2 b[3] = { + float2(1.0f, 0.0f), + trig_b[0] * moment_scale, + trig_b[1] * moment_scale + }; + // Compute a Cholesky factorization of the Toeplitz matrix + float D00 = RealPart(b[0]); + float InvD00 = 1.0f / D00; + float2 L10 = (b[1]) * InvD00; + float D11 = RealPart(b[0] - D00 * Multiply(L10, Conjugate(L10))); + float InvD11 = 1.0f / D11; + float2 L20 = (b[2]) * InvD00; + float2 L21 = (b[1] - D00 * Multiply(L20, Conjugate(L10))) * InvD11; + float D22 = RealPart(b[0] - D00 * Multiply(L20, Conjugate(L20)) - D11 * Multiply(L21, Conjugate(L21))); + float InvD22 = 1.0f / D22; + // Solve a linear system to get the relevant polynomial + float phase = mad(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y); + float2 circle_point; + sincos(phase, circle_point.y, circle_point.x); + float2 c[3] = { + float2(1.0f,0.0f), + circle_point, + Multiply(circle_point, circle_point) + }; + c[1] -= Multiply(L10, c[0]); + c[2] -= Multiply(L20, c[0]) + Multiply(L21, c[1]); + c[0] *= InvD00; + c[1] *= InvD11; + c[2] *= InvD22; + c[1] -= Multiply(Conjugate(L21), c[2]); + c[0] -= Multiply(Conjugate(L10), c[1]) + Multiply(Conjugate(L20), c[2]); + // Compute roots of the polynomial + float2 pRoot[2]; + SolveQuadratic(pRoot, Conjugate(c[2]), Conjugate(c[1]), Conjugate(c[0])); + // Figure out how to weight the weights + float depth_parameter = circleToParameter(circle_point); + float3 weight_factor; + weight_factor[0] = overestimation; + [unroll] + for (int i = 0; i != 2; ++i) + { + float root_parameter = circleToParameter(pRoot[i]); + weight_factor[i + 1] = getRootWeightFactor(depth_parameter, root_parameter, wrapping_zone_parameters); + } + // Compute the appropriate linear combination of weights + float2 z[3] = { circle_point, pRoot[0], pRoot[1] }; + float f0 = weight_factor[0]; + float f1 = weight_factor[1]; + float f2 = weight_factor[2]; + float2 f01 = Divide(f1 - f0, z[1] - z[0]); + float2 f12 = Divide(f2 - f1, z[2] - z[1]); + float2 f012 = Divide(f12 - f01, z[2] - z[0]); + float2 polynomial[3]; + polynomial[0] = f012; + polynomial[1] = polynomial[0]; + polynomial[0] = f01 - Multiply(polynomial[0], z[1]); + polynomial[2] = polynomial[1]; + polynomial[1] = polynomial[0] - Multiply(polynomial[1], z[0]); + polynomial[0] = f0 - Multiply(polynomial[0], z[0]); + float weight_sum = 0.0f; + weight_sum += RealPart(Multiply(b[0], polynomial[0])); + weight_sum += RealPart(Multiply(b[1], polynomial[1])); + weight_sum += RealPart(Multiply(b[2], polynomial[2])); + // Turn the normalized absorbance into transmittance + return exp(-b_0 * weight_sum); +} + +/*! This function reconstructs the transmittance at the given depth from three + normalized trigonometric moments. */ +float ComputeTransmittanceTrigonometric(float b_0, float2 trig_b[3], float depth, float bias, float overestimation, float4 wrapping_zone_parameters) +{ + // Apply biasing and reformat the inputs a little bit + float moment_scale = 1.0f - bias; + float2 b[4] = { + float2(1.0f, 0.0f), + trig_b[0] * moment_scale, + trig_b[1] * moment_scale, + trig_b[2] * moment_scale + }; + // Compute a Cholesky factorization of the Toeplitz matrix + float D00 = RealPart(b[0]); + float InvD00 = 1.0f / D00; + float2 L10 = (b[1]) * InvD00; + float D11 = RealPart(b[0] - D00 * Multiply(L10, Conjugate(L10))); + float InvD11 = 1.0f / D11; + float2 L20 = (b[2]) * InvD00; + float2 L21 = (b[1] - D00 * Multiply(L20, Conjugate(L10))) * InvD11; + float D22 = RealPart(b[0] - D00 * Multiply(L20, Conjugate(L20)) - D11 * Multiply(L21, Conjugate(L21))); + float InvD22 = 1.0f / D22; + float2 L30 = (b[3]) * InvD00; + float2 L31 = (b[2] - D00 * Multiply(L30, Conjugate(L10))) * InvD11; + float2 L32 = (b[1] - D00 * Multiply(L30, Conjugate(L20)) - D11 * Multiply(L31, Conjugate(L21))) * InvD22; + float D33 = RealPart(b[0] - D00 * Multiply(L30, Conjugate(L30)) - D11 * Multiply(L31, Conjugate(L31)) - D22 * Multiply(L32, Conjugate(L32))); + float InvD33 = 1.0f / D33; + // Solve a linear system to get the relevant polynomial + float phase = mad(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y); + float2 circle_point; + sincos(phase, circle_point.y, circle_point.x); + float2 circle_point_pow2 = Multiply(circle_point, circle_point); + float2 c[4] = { + float2(1.0f,0.0f), + circle_point, + circle_point_pow2, + Multiply(circle_point, circle_point_pow2) + }; + c[1] -= Multiply(L10, c[0]); + c[2] -= Multiply(L20, c[0]) + Multiply(L21, c[1]); + c[3] -= Multiply(L30, c[0]) + Multiply(L31, c[1]) + Multiply(L32, c[2]); + c[0] *= InvD00; + c[1] *= InvD11; + c[2] *= InvD22; + c[3] *= InvD33; + c[2] -= Multiply(Conjugate(L32), c[3]); + c[1] -= Multiply(Conjugate(L21), c[2]) + Multiply(Conjugate(L31), c[3]); + c[0] -= Multiply(Conjugate(L10), c[1]) + Multiply(Conjugate(L20), c[2]) + Multiply(Conjugate(L30), c[3]); + // Compute roots of the polynomial + float2 pRoot[3]; + SolveCubicBlinn(pRoot, Conjugate(c[3]), Conjugate(c[2]), Conjugate(c[1]), Conjugate(c[0])); + // The roots are known to be normalized but for reasons of numerical + // stability it can be better to enforce that + //pRoot[0]=normalize(pRoot[0]); + //pRoot[1]=normalize(pRoot[1]); + //pRoot[2]=normalize(pRoot[2]); + // Figure out how to weight the weights + float depth_parameter = circleToParameter(circle_point); + float4 weight_factor; + weight_factor[0] = overestimation; + [unroll] + for (int i = 0; i != 3; ++i) + { + float root_parameter = circleToParameter(pRoot[i]); + weight_factor[i + 1] = getRootWeightFactor(depth_parameter, root_parameter, wrapping_zone_parameters); + } + // Compute the appropriate linear combination of weights + float2 z[4] = { circle_point, pRoot[0], pRoot[1], pRoot[2] }; + float f0 = weight_factor[0]; + float f1 = weight_factor[1]; + float f2 = weight_factor[2]; + float f3 = weight_factor[3]; + float2 f01 = Divide(f1 - f0, z[1] - z[0]); + float2 f12 = Divide(f2 - f1, z[2] - z[1]); + float2 f23 = Divide(f3 - f2, z[3] - z[2]); + float2 f012 = Divide(f12 - f01, z[2] - z[0]); + float2 f123 = Divide(f23 - f12, z[3] - z[1]); + float2 f0123 = Divide(f123 - f012, z[3] - z[0]); + float2 polynomial[4]; + polynomial[0] = f0123; + polynomial[1] = polynomial[0]; + polynomial[0] = f012 - Multiply(polynomial[0], z[2]); + polynomial[2] = polynomial[1]; + polynomial[1] = polynomial[0] - Multiply(polynomial[1], z[1]); + polynomial[0] = f01 - Multiply(polynomial[0], z[1]); + polynomial[3] = polynomial[2]; + polynomial[2] = polynomial[1] - Multiply(polynomial[2], z[0]); + polynomial[1] = polynomial[0] - Multiply(polynomial[1], z[0]); + polynomial[0] = f0 - Multiply(polynomial[0], z[0]); + float weight_sum = 0; + weight_sum += RealPart(Multiply(b[0], polynomial[0])); + weight_sum += RealPart(Multiply(b[1], polynomial[1])); + weight_sum += RealPart(Multiply(b[2], polynomial[2])); + weight_sum += RealPart(Multiply(b[3], polynomial[3])); + // Turn the normalized absorbance into transmittance + return exp(-b_0 * weight_sum); +} + +/*! This function reconstructs the transmittance at the given depth from four + normalized trigonometric moments.*/ +float ComputeTransmittanceTrigonometric(float b_0, float2 trig_b[4], float depth, float bias, float overestimation, float4 wrapping_zone_parameters) +{ + // Apply biasing and reformat the inputs a little bit + float moment_scale = 1.0f - bias; + float2 b[5] = { + float2(1.0f, 0.0f), + trig_b[0] * moment_scale, + trig_b[1] * moment_scale, + trig_b[2] * moment_scale, + trig_b[3] * moment_scale + }; + // Compute a Cholesky factorization of the Toeplitz matrix + float D00 = RealPart(b[0]); + float InvD00 = 1.0 / D00; + float2 L10 = (b[1]) * InvD00; + float D11 = RealPart(b[0] - D00 * Multiply(L10, Conjugate(L10))); + float InvD11 = 1.0 / D11; + float2 L20 = (b[2]) * InvD00; + float2 L21 = (b[1] - D00 * Multiply(L20, Conjugate(L10))) * InvD11; + float D22 = RealPart(b[0] - D00 * Multiply(L20, Conjugate(L20)) - D11 * Multiply(L21, Conjugate(L21))); + float InvD22 = 1.0 / D22; + float2 L30 = (b[3]) * InvD00; + float2 L31 = (b[2] - D00 * Multiply(L30, Conjugate(L10))) * InvD11; + float2 L32 = (b[1] - D00 * Multiply(L30, Conjugate(L20)) - D11 * Multiply(L31, Conjugate(L21))) * InvD22; + float D33 = RealPart(b[0] - D00 * Multiply(L30, Conjugate(L30)) - D11 * Multiply(L31, Conjugate(L31)) - D22 * Multiply(L32, Conjugate(L32))); + float InvD33 = 1.0 / D33; + float2 L40 = (b[4]) * InvD00; + float2 L41 = (b[3] - D00 * Multiply(L40, Conjugate(L10))) * InvD11; + float2 L42 = (b[2] - D00 * Multiply(L40, Conjugate(L20)) - D11 * Multiply(L41, Conjugate(L21))) * InvD22; + float2 L43 = (b[1] - D00 * Multiply(L40, Conjugate(L30)) - D11 * Multiply(L41, Conjugate(L31)) - D22 * Multiply(L42, Conjugate(L32))) * InvD33; + float D44 = RealPart(b[0] - D00 * Multiply(L40, Conjugate(L40)) - D11 * Multiply(L41, Conjugate(L41)) - D22 * Multiply(L42, Conjugate(L42)) - D33 * Multiply(L43, Conjugate(L43))); + float InvD44 = 1.0 / D44; + // Solve a linear system to get the relevant polynomial + float phase = mad(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y); + float2 circle_point; + sincos(phase, circle_point.y, circle_point.x); + float2 circle_point_pow2 = Multiply(circle_point, circle_point); + float2 c[5] = { + float2(1.0f,0.0f), + circle_point, + circle_point_pow2, + Multiply(circle_point, circle_point_pow2), + Multiply(circle_point_pow2, circle_point_pow2) + }; + c[1] -= Multiply(L10, c[0]); + c[2] -= Multiply(L20, c[0]) + Multiply(L21, c[1]); + c[3] -= Multiply(L30, c[0]) + Multiply(L31, c[1]) + Multiply(L32, c[2]); + c[4] -= Multiply(L40, c[0]) + Multiply(L41, c[1]) + Multiply(L42, c[2]) + Multiply(L43, c[3]); + c[0] *= InvD00; + c[1] *= InvD11; + c[2] *= InvD22; + c[3] *= InvD33; + c[4] *= InvD44; + c[3] -= Multiply(Conjugate(L43), c[4]); + c[2] -= Multiply(Conjugate(L32), c[3]) + Multiply(Conjugate(L42), c[4]); + c[1] -= Multiply(Conjugate(L21), c[2]) + Multiply(Conjugate(L31), c[3]) + Multiply(Conjugate(L41), c[4]); + c[0] -= Multiply(Conjugate(L10), c[1]) + Multiply(Conjugate(L20), c[2]) + Multiply(Conjugate(L30), c[3]) + Multiply(Conjugate(L40), c[4]); + // Compute roots of the polynomial + float2 pRoot[4]; + SolveQuarticNeumark(pRoot, Conjugate(c[4]), Conjugate(c[3]), Conjugate(c[2]), Conjugate(c[1]), Conjugate(c[0])); + // Figure out how to weight the weights + float depth_parameter = circleToParameter(circle_point); + float weight_factor[5]; + weight_factor[0] = overestimation; + [unroll] + for (int i = 0; i != 4; ++i) + { + float root_parameter = circleToParameter(pRoot[i]); + weight_factor[i + 1] = getRootWeightFactor(depth_parameter, root_parameter, wrapping_zone_parameters); + } + // Compute the appropriate linear combination of weights + float2 z[5] = { circle_point, pRoot[0], pRoot[1], pRoot[2], pRoot[3] }; + float f0 = weight_factor[0]; + float f1 = weight_factor[1]; + float f2 = weight_factor[2]; + float f3 = weight_factor[3]; + float f4 = weight_factor[4]; + float2 f01 = Divide(f1 - f0, z[1] - z[0]); + float2 f12 = Divide(f2 - f1, z[2] - z[1]); + float2 f23 = Divide(f3 - f2, z[3] - z[2]); + float2 f34 = Divide(f4 - f3, z[4] - z[3]); + float2 f012 = Divide(f12 - f01, z[2] - z[0]); + float2 f123 = Divide(f23 - f12, z[3] - z[1]); + float2 f234 = Divide(f34 - f23, z[4] - z[2]); + float2 f0123 = Divide(f123 - f012, z[3] - z[0]); + float2 f1234 = Divide(f234 - f123, z[4] - z[1]); + float2 f01234 = Divide(f1234 - f0123, z[4] - z[0]); + float2 polynomial[5]; + polynomial[0] = f01234; + polynomial[1] = polynomial[0]; + polynomial[0] = f0123 - Multiply(polynomial[0], z[3]); + polynomial[2] = polynomial[1]; + polynomial[1] = polynomial[0] - Multiply(polynomial[1], z[2]); + polynomial[0] = f012 - Multiply(polynomial[0], z[2]); + polynomial[3] = polynomial[2]; + polynomial[2] = polynomial[1] - Multiply(polynomial[2], z[1]); + polynomial[1] = polynomial[0] - Multiply(polynomial[1], z[1]); + polynomial[0] = f01 - Multiply(polynomial[0], z[1]); + polynomial[4] = polynomial[3]; + polynomial[3] = polynomial[2] - Multiply(polynomial[3], z[0]); + polynomial[2] = polynomial[1] - Multiply(polynomial[2], z[0]); + polynomial[1] = polynomial[0] - Multiply(polynomial[1], z[0]); + polynomial[0] = f0 - Multiply(polynomial[0], z[0]); + float weight_sum = 0; + weight_sum += RealPart(Multiply(b[0], polynomial[0])); + weight_sum += RealPart(Multiply(b[1], polynomial[1])); + weight_sum += RealPart(Multiply(b[2], polynomial[2])); + weight_sum += RealPart(Multiply(b[3], polynomial[3])); + weight_sum += RealPart(Multiply(b[4], polynomial[4])); + // Turn the normalized absorbance into transmittance + return exp(-b_0 * weight_sum); +} +#endif \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl.meta new file mode 100644 index 0000000..bb3d35b --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6aa37c869516b6b4abf1ddc58653e893 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl b/Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl new file mode 100644 index 0000000..e941fbd --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl @@ -0,0 +1,17 @@ +float2 _LogViewDepthMinDelta; +float WarpDepth(float vd) +{ + //return (log(vd) - _LogViewDepthMinDelta.x) / _LogViewDepthMinDelta.y * 2 - 1; + //return (log(vd) - _LogViewDepthMinDelta.x) / _LogViewDepthMinDelta.y; + //return vd; + //return log(vd) * 2 - 1; + //return (vd - _LogViewDepthMinDelta.x) / _LogViewDepthMinDelta.y * 2 - 1; + + //return vd * 2 - 1; + //return (log(vd * 2 - 1) - _LogViewDepthMinDelta.x) / _LogViewDepthMinDelta.y * 2 - 1; + + //return (log(vd) - _LogViewDepthMinDelta.x) / _LogViewDepthMinDelta.y * 2 - 1; + return saturate((log(vd) - _LogViewDepthMinDelta.x) / _LogViewDepthMinDelta.y) * 2 - 1; +} + +// NOTE: vd (z/depth) are computed from linear view-space depth values \ No newline at end of file diff --git a/Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl.meta b/Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl.meta new file mode 100644 index 0000000..fef96c3 --- /dev/null +++ b/Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 174d761f60c0b3543996519b15424503 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Features/OIT/SortTriangles.meta b/Assets/Scripts/Features/OIT/SortTriangles.meta new file mode 100644 index 0000000..62d9ddb --- /dev/null +++ b/Assets/Scripts/Features/OIT/SortTriangles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53073e24ceed8514ea066c180cf5cdd8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Mobile/Mobile_High_Renderer.asset b/Assets/Settings/Mobile/Mobile_High_Renderer.asset index 665d153..e455224 100644 --- a/Assets/Settings/Mobile/Mobile_High_Renderer.asset +++ b/Assets/Settings/Mobile/Mobile_High_Renderer.asset @@ -26,7 +26,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 2f83dd6eb48aa6848950f8a0f61a70de, type: 3} m_Name: LinkedListOITFeature m_EditorClassIdentifier: - m_Active: 1 + m_Active: 0 settings: RenderPassEvent: 500 ComputeShader: {fileID: 7200000, guid: eb30737736968d64e99cd6b7e2cc9efb, type: 3} @@ -125,6 +125,48 @@ MonoBehaviour: cutoffThreshold: 0.2 binaryValue: 0.9 flags: 13 +--- !u!114 &-7198069835786880352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4854a869b24c78844a4c077509f99b4f, type: 3} + m_Name: MOITFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + renderPassEvent: 450 + settings: + momentsCount: 4 + momentPrecision: 32 + trigonometric: 0 + boundsType: 1 + onlyVisibleRenderers: 0 + layerMask: + serializedVersion: 2 + m_Bits: 4294967295 + renderQueueMin: 2501 + renderQueueMax: 3000 + compositeMaterial: {fileID: 2100000, guid: f5b0014f90114064c8200b5c9ac93932, type: 2} + sortBackToFront: 0 + debugMakeMOITTexGlobal: 0 + biasSettings: + Moments4Half: 0.00006 + Moments4Single: 0.0000005 + Moments6Half: 0.0006 + Moments6Single: 0.000005 + Moments8Half: 0.0025 + Moments8Single: 0.00005 + Trigonometric2Half: 0.0004 + Trigonometric2Single: 0.0000004 + Trigonometric3Half: 0.00065 + Trigonometric3Single: 0.0000008 + Trigonometric4Half: 0.00085 + Trigonometric4Single: 0.0000015 --- !u!114 &-7143664486661302651 MonoBehaviour: m_ObjectHideFlags: 0 @@ -376,8 +418,9 @@ MonoBehaviour: - {fileID: -7143664486661302651} - {fileID: 654879339943129409} - {fileID: -8044648393505963816} - m_RendererFeatureMap: bc3f630842f2e70dd6a559c442a94bfd4529d15534f2d3de228858dca8d12222716523fbf3439fdb7a327b7bff4bdd446ac59dfa966ffa88ca6373cd5da9013d6cff55ca297e5e908a7b3653203b82383b2141bb05fbe69aec5704e48e2763e90bc6ff9f19caa7686c79a6bb3bb89a50faad0fe75217cdb485d6fa85ff9adc9c41710d3c4a991609d8002992e8aa5b90 - m_UseNativeRenderPass: 0 + - {fileID: -7198069835786880352} + m_RendererFeatureMap: bc3f630842f2e70dd6a559c442a94bfd4529d15534f2d3de228858dca8d12222716523fbf3439fdb7a327b7bff4bdd446ac59dfa966ffa88ca6373cd5da9013d6cff55ca297e5e908a7b3653203b82383b2141bb05fbe69aec5704e48e2763e90bc6ff9f19caa7686c79a6bb3bb89a50faad0fe75217cdb485d6fa85ff9adc9c41710d3c4a991609d8002992e8aa5b90a0fa77119f511b9c + m_UseNativeRenderPass: 1 postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} shaders: blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3}