sync
This commit is contained in:
parent
5d3b01ec25
commit
0bbac083b5
@ -21,7 +21,7 @@ Material:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: fish_red_tail_barracuda_mat_ll
|
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_Parent: {fileID: 0}
|
||||||
m_ModifiedSerializedProperties: 0
|
m_ModifiedSerializedProperties: 0
|
||||||
m_ValidKeywords: []
|
m_ValidKeywords: []
|
||||||
|
|||||||
@ -22509,7 +22509,7 @@ MeshRenderer:
|
|||||||
m_RendererPriority: 0
|
m_RendererPriority: 0
|
||||||
m_Materials:
|
m_Materials:
|
||||||
- {fileID: 2100000, guid: 82f089674b537fe42b84f66f22c4b13f, type: 2}
|
- {fileID: 2100000, guid: 82f089674b537fe42b84f66f22c4b13f, type: 2}
|
||||||
- {fileID: 2100000, guid: 2d10684597fead649b048a865154ad79, type: 2}
|
- {fileID: 2100000, guid: 872b4d67fd3bbd14caa9aea720bd1b75, type: 2}
|
||||||
m_StaticBatchInfo:
|
m_StaticBatchInfo:
|
||||||
firstSubMesh: 0
|
firstSubMesh: 0
|
||||||
subMeshCount: 0
|
subMeshCount: 0
|
||||||
@ -22548,7 +22548,7 @@ Transform:
|
|||||||
m_GameObject: {fileID: 1335403876}
|
m_GameObject: {fileID: 1335403876}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0.000000018075937, y: -0.5621158, z: -0.000000012285431, w: 0.8270586}
|
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_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
@ -29247,7 +29247,7 @@ Transform:
|
|||||||
m_GameObject: {fileID: 1829397597}
|
m_GameObject: {fileID: 1829397597}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
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_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
@ -33661,7 +33661,7 @@ GameObject:
|
|||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
m_IsActive: 0
|
m_IsActive: 1
|
||||||
--- !u!4 &2128448439
|
--- !u!4 &2128448439
|
||||||
Transform:
|
Transform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
110
Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl
Normal file
110
Assets/Scripts/Features/OIT/MOIT/GenerateMoments.hlsl
Normal file
@ -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;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d94ff48de7281de41b27523cbe5b4b82
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
30
Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat
Normal file
30
Assets/Scripts/Features/OIT/MOIT/Hidden_MOITComposite.mat
Normal file
@ -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: []
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f5b0014f90114064c8200b5c9ac93932
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
36
Assets/Scripts/Features/OIT/MOIT/MOITBias.cs
Normal file
36
Assets/Scripts/Features/OIT/MOIT/MOITBias.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
11
Assets/Scripts/Features/OIT/MOIT/MOITBias.cs.meta
Normal file
11
Assets/Scripts/Features/OIT/MOIT/MOITBias.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b50afbba4415dd24083a909b94e8ea98
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
113
Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader
Normal file
113
Assets/Scripts/Features/OIT/MOIT/MOITComposite.shader
Normal file
@ -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
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1e94033f658200a4698edae134542fa2
|
||||||
|
ShaderImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
defaultTextures: []
|
||||||
|
nonModifiableTextures: []
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,14 +1,45 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Runtime.ConstrainedExecution;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Experimental.Rendering.RenderGraphModule;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using UnityEngine.Rendering.Universal;
|
using UnityEngine.Rendering.Universal;
|
||||||
|
|
||||||
[DisallowMultipleRendererFeature("Moment Based Order-Independent Transparency")]
|
[DisallowMultipleRendererFeature("Moment Based Order-Independent Transparency")]
|
||||||
public class MOITFeature : ScriptableRendererFeature
|
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]
|
[Serializable]
|
||||||
class Settings
|
class Settings
|
||||||
{
|
{
|
||||||
|
[SerializeField]
|
||||||
|
internal RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingTransparents;
|
||||||
|
[SerializeField]
|
||||||
|
internal MOITSettings settings;
|
||||||
|
[SerializeField]
|
||||||
|
internal MOITBias biasSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
@ -32,17 +63,252 @@ public class MOITFeature : ScriptableRendererFeature
|
|||||||
pass = new(settings);
|
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)
|
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)
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs
Normal file
31
Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
11
Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs.meta
Normal file
11
Assets/Scripts/Features/OIT/MOIT/MOITSettings.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ddbee5a74829c549b5e5b0aeb26ac63
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
395
Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl
Normal file
395
Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl
Normal file
@ -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
|
||||||
7
Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl.meta
Normal file
7
Assets/Scripts/Features/OIT/MOIT/MomentMath.hlsl.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 01ecfba35fc1e0743acd03dfde076125
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
20
Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl
Normal file
20
Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl
Normal file
@ -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
|
||||||
|
};
|
||||||
7
Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl.meta
Normal file
7
Assets/Scripts/Features/OIT/MOIT/MomentOutput.hlsl.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b726e2096ac821a4696aa328564a4e3c
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
98
Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl
Normal file
98
Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl
Normal file
@ -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);
|
||||||
|
}
|
||||||
7
Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl.meta
Normal file
7
Assets/Scripts/Features/OIT/MOIT/Quantization.hlsl.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 280699927ed265b4a8641989996cdec3
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
131
Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl
Normal file
131
Assets/Scripts/Features/OIT/MOIT/ResolveMoments.hlsl
Normal file
@ -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
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3ebfeb4e0588c2e4c9740481884ec4b5
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
510
Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl
Normal file
510
Assets/Scripts/Features/OIT/MOIT/TrigonometricMomentMath.hlsl
Normal file
@ -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
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6aa37c869516b6b4abf1ddc58653e893
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
17
Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl
Normal file
17
Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl
Normal file
@ -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
|
||||||
7
Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl.meta
Normal file
7
Assets/Scripts/Features/OIT/MOIT/WarpDepth.hlsl.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 174d761f60c0b3543996519b15424503
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Scripts/Features/OIT/SortTriangles.meta
Normal file
8
Assets/Scripts/Features/OIT/SortTriangles.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 53073e24ceed8514ea066c180cf5cdd8
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -26,7 +26,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 2f83dd6eb48aa6848950f8a0f61a70de, type: 3}
|
m_Script: {fileID: 11500000, guid: 2f83dd6eb48aa6848950f8a0f61a70de, type: 3}
|
||||||
m_Name: LinkedListOITFeature
|
m_Name: LinkedListOITFeature
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_Active: 1
|
m_Active: 0
|
||||||
settings:
|
settings:
|
||||||
RenderPassEvent: 500
|
RenderPassEvent: 500
|
||||||
ComputeShader: {fileID: 7200000, guid: eb30737736968d64e99cd6b7e2cc9efb, type: 3}
|
ComputeShader: {fileID: 7200000, guid: eb30737736968d64e99cd6b7e2cc9efb, type: 3}
|
||||||
@ -125,6 +125,48 @@ MonoBehaviour:
|
|||||||
cutoffThreshold: 0.2
|
cutoffThreshold: 0.2
|
||||||
binaryValue: 0.9
|
binaryValue: 0.9
|
||||||
flags: 13
|
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
|
--- !u!114 &-7143664486661302651
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -376,8 +418,9 @@ MonoBehaviour:
|
|||||||
- {fileID: -7143664486661302651}
|
- {fileID: -7143664486661302651}
|
||||||
- {fileID: 654879339943129409}
|
- {fileID: 654879339943129409}
|
||||||
- {fileID: -8044648393505963816}
|
- {fileID: -8044648393505963816}
|
||||||
m_RendererFeatureMap: bc3f630842f2e70dd6a559c442a94bfd4529d15534f2d3de228858dca8d12222716523fbf3439fdb7a327b7bff4bdd446ac59dfa966ffa88ca6373cd5da9013d6cff55ca297e5e908a7b3653203b82383b2141bb05fbe69aec5704e48e2763e90bc6ff9f19caa7686c79a6bb3bb89a50faad0fe75217cdb485d6fa85ff9adc9c41710d3c4a991609d8002992e8aa5b90
|
- {fileID: -7198069835786880352}
|
||||||
m_UseNativeRenderPass: 0
|
m_RendererFeatureMap: bc3f630842f2e70dd6a559c442a94bfd4529d15534f2d3de228858dca8d12222716523fbf3439fdb7a327b7bff4bdd446ac59dfa966ffa88ca6373cd5da9013d6cff55ca297e5e908a7b3653203b82383b2141bb05fbe69aec5704e48e2763e90bc6ff9f19caa7686c79a6bb3bb89a50faad0fe75217cdb485d6fa85ff9adc9c41710d3c4a991609d8002992e8aa5b90a0fa77119f511b9c
|
||||||
|
m_UseNativeRenderPass: 1
|
||||||
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
|
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
|
||||||
shaders:
|
shaders:
|
||||||
blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3}
|
blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user