This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
// This file assume SHADER_API_D3D11 is defined
#define UNITY_UV_STARTS_AT_TOP 1
#define UNITY_REVERSED_Z 1
#define UNITY_NEAR_CLIP_VALUE (1.0)
// This value will not go through any matrix projection conversion
#define UNITY_RAW_FAR_CLIP_VALUE (0.0)
#define VERTEXID_SEMANTIC SV_VertexID
#define INSTANCEID_SEMANTIC SV_InstanceID
#define FRONT_FACE_SEMANTIC SV_IsFrontFace
#define FRONT_FACE_TYPE bool
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL) ? (FRONT) : (BACK))
#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
#define PLATFORM_SUPPORTS_EXPLICIT_BINDING
#define PLATFORM_NEEDS_UNORM_UAV_SPECIFIER
#define PLATFORM_SUPPORTS_BUFFER_ATOMICS_IN_PIXEL_SHADER
#define PLATFORM_SUPPORTS_PRIMITIVE_ID_IN_PIXEL_SHADER
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)

View File

@@ -0,0 +1,153 @@
#ifndef SHADER_API_GLCORE
#error GLES.hlsl should not be included if SHADER_API_GLCORE is not defined
#endif
#define UNITY_UV_STARTS_AT_TOP 0
#define UNITY_REVERSED_Z 0
#define UNITY_NEAR_CLIP_VALUE (-1.0)
// This value will not go through any matrix projection convertion
#define UNITY_RAW_FAR_CLIP_VALUE (1.0)
#define VERTEXID_SEMANTIC SV_VertexID
#define INSTANCEID_SEMANTIC SV_InstanceID
#define FRONT_FACE_SEMANTIC VFACE
#define FRONT_FACE_TYPE float
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL > 0.0) ? (FRONT) : (BACK))
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLCORE
#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
#define PLATFORM_SUPPORTS_EXPLICIT_BINDING
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 46)
#define OPENGL4_1_SM5 1
#else
#define OPENGL4_1_SM5 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_BIAS)
#else
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)textureName.SampleBias(samplerName, float4(coord3, index), bias)
#endif
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#if OPENGL4_1_SM5
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#else
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D_ARRAY)
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE_ARRAY)
#endif

View File

@@ -0,0 +1,164 @@
#ifndef SHADER_API_GLES
#error GLES.hlsl should not be included if SHADER_API_GLES is not defined
#endif
#define UNITY_UV_STARTS_AT_TOP 0
#define UNITY_REVERSED_Z 0
#define UNITY_NEAR_CLIP_VALUE (-1.0)
// This value will not go through any matrix projection convertion
#define UNITY_RAW_FAR_CLIP_VALUE (1.0)
#define VERTEXID_SEMANTIC gl_VertexID
#define INSTANCEID_SEMANTIC gl_InstanceID
#define FRONT_FACE_SEMANTIC VFACE
#define FRONT_FACE_TYPE float
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL > 0.0) ? (FRONT) : (BACK))
#define CBUFFER_START(name)
#define CBUFFER_END
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
#define uint int
#define rcp(x) 1.0 / (x)
#define ddx_fine ddx
#define ddy_fine ddy
#define asfloat
#define asuint(x) asint(x)
#define f32tof16
#define f16tof32
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// GLES2 might not have shadow hardware comparison support
#if defined(UNITY_ENABLE_NATIVE_SHADOWS_LOOKUPS)
#define SHADOW2D_TEXTURE_AND_SAMPLER sampler2DShadow
#define SHADOWCUBE_TEXTURE_AND_SAMPLER samplerCUBEShadow
#define SHADOW2D_SAMPLE(textureName, samplerName, coord3) shadow2D(textureName, coord3)
#define SHADOWCUBE_SAMPLE(textureName, samplerName, coord4) ((texCUBE(textureName,(coord4).xyz) < (coord4).w) ? 0.0 : 1.0)
#else
// emulate hardware comparison
#define SHADOW2D_TEXTURE_AND_SAMPLER sampler2D_float
#define SHADOWCUBE_TEXTURE_AND_SAMPLER samplerCUBE_float
#define SHADOW2D_SAMPLE(textureName, samplerName, coord3) ((SAMPLE_DEPTH_TEXTURE(textureName, samplerName, (coord3).xy) < (coord3).z) ? 0.0 : 1.0)
#define SHADOWCUBE_SAMPLE(textureName, samplerName, coord4) ((texCUBE(textureName,(coord4).xyz).r < (coord4).w) ? 0.0 : 1.0)
#endif
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2
// Texture abstraction
#define TEXTURE2D(textureName) sampler2D textureName
#define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray
#define TEXTURECUBE(textureName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray
#define TEXTURE3D(textureName) sampler3D textureName
#define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray
#define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to textureCubeArray
#define TEXTURE3D_FLOAT(textureName) sampler3D_float textureName
#define TEXTURE2D_HALF(textureName) sampler2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray
#define TEXTURECUBE_HALF(textureName) samplerCUBE_half textureName
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to textureCubeArray
#define TEXTURE3D_HALF(textureName) sampler3D_half textureName
#define TEXTURE2D_SHADOW(textureName) SHADOW2D_TEXTURE_AND_SAMPLER textureName
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURECUBE_SHADOW(textureName) // No support to texture array
#define TEXTURECUBE_SHADOW(textureName) SHADOWCUBE_TEXTURE_AND_SAMPLER textureName
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_SHADOW(textureName) // No support to texture array
#define RW_TEXTURE2D(type, textureNam) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2D)
#define RW_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2DArray)
#define RW_TEXTURE3D(type, textureNam) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture3D)
#define SAMPLER(samplerName)
#define SAMPLER_CMP(samplerName)
#define ASSIGN_SAMPLER(samplerName, samplerValue)
#define TEXTURE2D_PARAM(textureName, samplerName) sampler2D textureName
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) samplerCUBE textureName
#define TEXTURECUBE_PARAM(textureName, samplerName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) samplerCUBE textureName
#define TEXTURE3D_PARAM(textureName, samplerName) sampler3D textureName
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) SHADOW2D_TEXTURE_AND_SAMPLER textureName
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) SHADOWCUBE_TEXTURE_AND_SAMPLER textureName
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) SHADOWCUBE_TEXTURE_AND_SAMPLER textureName
#define TEXTURE2D_ARGS(textureName, samplerName) textureName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)
#if (SHADER_TARGET >= 30)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod))
#else
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod)
#endif
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias))
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) texCUBE(textureName, coord3)
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) texCUBEbias(textureName, float4(coord3, bias))
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_BIAS)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) tex3D(textureName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE3D_LOD)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) SHADOW2D_SAMPLE(textureName, samplerName, coord3)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_SHADOW)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) SHADOWCUBE_SAMPLE(textureName, samplerName, coord4)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_SHADOW)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
// Not supported. Can't define as error because shader library is calling these functions.
#define LOAD_TEXTURE2D(textureName, unCoord2) half4(0, 0, 0, 0)
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) half4(0, 0, 0, 0)
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) half4(0, 0, 0, 0)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) half4(0, 0, 0, 0)
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) half4(0, 0, 0, 0)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) half4(0, 0, 0, 0)
#define LOAD_TEXTURE3D(textureName, unCoord3) ERROR_ON_UNSUPPORTED_FUNCTION(LOAD_TEXTURE3D)
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) ERROR_ON_UNSUPPORTED_FUNCTION(LOAD_TEXTURE3D_LOD)
// Gather not supported. Fallback to regular texture sampling.
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D_ARRAY)
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE_ARRAY)
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_RED_TEXTURE2D)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_GREEN_TEXTURE2D)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_BLUE_TEXTURE2D)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_ALPHA_TEXTURE2D)

View File

@@ -0,0 +1,168 @@
#ifndef SHADER_API_GLES3
#error GLES.hlsl should not be included if SHADER_API_GLES3 is not defined
#endif
#define UNITY_UV_STARTS_AT_TOP 0
#define UNITY_REVERSED_Z 0
#define UNITY_NEAR_CLIP_VALUE (-1.0)
// This value will not go through any matrix projection convertion
#define UNITY_RAW_FAR_CLIP_VALUE (1.0)
#define VERTEXID_SEMANTIC SV_VertexID
#define INSTANCEID_SEMANTIC SV_InstanceID
#define FRONT_FACE_SEMANTIC VFACE
#define FRONT_FACE_TYPE float
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL > 0.0) ? (FRONT) : (BACK))
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 3.0
#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 40)
#define GLES3_1_AEP 1
#else
#define GLES3_1_AEP 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray_float textureName
#define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray_float textureName
#define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray_half textureName
#define TEXTURECUBE_HALF(textureName) TextureCube_half textureName
#define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray_half textureName
#define TEXTURE3D_HALF(textureName) Texture3D_half textureName
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#if GLES3_1_AEP
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#else
#define RW_TEXTURE2D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2D)
#define RW_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2DArray)
#define RW_TEXTURE3D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture3D)
#endif
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_LOD)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURECUBE_ARRAY_BIAS)
#else
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)textureName.SampleBias(samplerName, float4(coord3, index), bias)
#endif
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#if GLES3_1_AEP
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)
#else
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURE2D_ARRAY)
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_TEXTURECUBE_ARRAY)
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_RED_TEXTURE2D)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_GREEN_TEXTURE2D)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_BLUE_TEXTURE2D)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) ERROR_ON_UNSUPPORTED_FUNCTION(GATHER_ALPHA_TEXTURE2D)
#endif

View File

@@ -0,0 +1,135 @@
// This file assumes SHADER_API_METAL is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
#define UNITY_UV_STARTS_AT_TOP 1
#define UNITY_REVERSED_Z 1
#define UNITY_NEAR_CLIP_VALUE (1.0)
// This value will not go through any matrix projection conversion
#define UNITY_RAW_FAR_CLIP_VALUE (0.0)
#define VERTEXID_SEMANTIC SV_VertexID
#define INSTANCEID_SEMANTIC SV_InstanceID
#define FRONT_FACE_SEMANTIC SV_IsFrontFace
#define FRONT_FACE_TYPE bool
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL) ? (FRONT) : (BACK))
#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
#define PLATFORM_SUPPORTS_EXPLICIT_BINDING
#define PLATFORM_NEEDS_UNORM_UAV_SPECIFIER
#define PLATFORM_SUPPORTS_BUFFER_ATOMICS_IN_PIXEL_SHADER
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray_float textureName
#define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray_float textureName
#define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray_half textureName
#define TEXTURECUBE_HALF(textureName) TextureCube_half textureName
#define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray_half textureName
#define TEXTURE3D_HALF(textureName) Texture3D_half textureName
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)

View File

@@ -0,0 +1,134 @@
// This file assume SHADER_API_SWITCH is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
#define UNITY_UV_STARTS_AT_TOP 1
#define UNITY_REVERSED_Z 1
#define UNITY_NEAR_CLIP_VALUE (1.0)
// This value will not go through any matrix projection conversion
#define UNITY_RAW_FAR_CLIP_VALUE (0.0)
#define VERTEXID_SEMANTIC SV_VertexID
#define INSTANCEID_SEMANTIC SV_InstanceID
#define FRONT_FACE_SEMANTIC SV_IsFrontFace
#define FRONT_FACE_TYPE bool
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL) ? (FRONT) : (BACK))
#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
#define PLATFORM_SUPPORTS_EXPLICIT_BINDING
#define PLATFORM_NEEDS_UNORM_UAV_SPECIFIER
#define PLATFORM_LANE_COUNT 32
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray_float textureName
#define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray_float textureName
#define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray_half textureName
#define TEXTURECUBE_HALF(textureName) TextureCube_half textureName
#define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray_half textureName
#define TEXTURE3D_HALF(textureName) Texture3D_half textureName
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)

View File

@@ -0,0 +1,38 @@
// Wait for a fix from Trunk #error not supported yet
/*
#define REQUIRE_DEFINED(X_) \
#ifndef X_ \
#error X_ must be defined (in) the platform include \
#endif X_ \
REQUIRE_DEFINED(UNITY_UV_STARTS_AT_TOP)
REQUIRE_DEFINED(UNITY_REVERSED_Z)
REQUIRE_DEFINED(UNITY_NEAR_CLIP_VALUE)
REQUIRE_DEFINED(FACE)
REQUIRE_DEFINED(CBUFFER_START)
REQUIRE_DEFINED(CBUFFER_END)
REQUIRE_DEFINED(INITIALIZE_OUTPUT)
*/
// Default values for things that have not been defined in the platform headers
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif

View File

@@ -0,0 +1,136 @@
// This file assume SHADER_API_VULKAN is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
#define UNITY_UV_STARTS_AT_TOP 1
#define UNITY_REVERSED_Z 1
#define UNITY_NEAR_CLIP_VALUE (1.0)
// This value will not go through any matrix projection conversion
#define UNITY_RAW_FAR_CLIP_VALUE (0.0)
#define VERTEXID_SEMANTIC SV_VertexID
#define INSTANCEID_SEMANTIC SV_InstanceID
#define FRONT_FACE_SEMANTIC SV_IsFrontFace
#define FRONT_FACE_TYPE bool
#define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL) ? (FRONT) : (BACK))
#define CBUFFER_START(name) cbuffer name {
#define CBUFFER_END };
#define PLATFORM_SUPPORTS_EXPLICIT_BINDING
#define PLATFORM_NEEDS_UNORM_UAV_SPECIFIER
#define PLATFORM_SUPPORTS_BUFFER_ATOMICS_IN_PIXEL_SHADER
#define PLATFORM_SUPPORTS_PRIMITIVE_ID_IN_PIXEL_SHADER
// flow control attributes
#define UNITY_BRANCH [branch]
#define UNITY_FLATTEN [flatten]
#define UNITY_UNROLL [unroll]
#define UNITY_UNROLLX(_x) [unroll(_x)]
#define UNITY_LOOP [loop]
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray_float textureName
#define TEXTURECUBE_FLOAT(textureName) TextureCube_float textureName
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TextureCubeArray_float textureName
#define TEXTURE3D_FLOAT(textureName) Texture3D_float textureName
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray_half textureName
#define TEXTURECUBE_HALF(textureName) TextureCube_half textureName
#define TEXTURECUBE_ARRAY_HALF(textureName) TextureCubeArray_half textureName
#define TEXTURE3D_HALF(textureName) Texture3D_half textureName
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)

View File

@@ -0,0 +1,418 @@
#ifndef UNITY_AREA_LIGHTING_INCLUDED
#define UNITY_AREA_LIGHTING_INCLUDED
#define APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
#define APPROXIMATE_SPHERE_LIGHT_NUMERICALLY
// Not normalized by the factor of 1/TWO_PI.
real3 ComputeEdgeFactor(real3 V1, real3 V2)
{
real V1oV2 = dot(V1, V2);
real3 V1xV2 = cross(V1, V2);
#if 0
return normalize(V1xV2) * acos(V1oV2));
#else
// Approximate: { y = rsqrt(1.0 - V1oV2 * V1oV2) * acos(V1oV2) } on [0, 1].
// Fit: HornerForm[MiniMaxApproximation[ArcCos[x]/Sqrt[1 - x^2], {x, {0, 1 - $MachineEpsilon}, 6, 0}][[2, 1]]].
// Maximum relative error: 2.6855360216340534 * 10^-6. Intensities up to 1000 are artifact-free.
real x = abs(V1oV2);
real y = 1.5707921083647782 + x * (-0.9995697178013095 + x * (0.778026455830408 + x * (-0.6173111361273548 + x * (0.4202724111150622 + x * (-0.19452783598217288 + x * 0.04232040013661036)))));
if (V1oV2 < 0)
{
// Undo range reduction.
const float epsilon = 1e-5f;
y = PI * rsqrt(max(epsilon, saturate(1 - V1oV2 * V1oV2))) - y;
}
return V1xV2 * y;
#endif
}
// Not normalized by the factor of 1/TWO_PI.
// Ref: Improving radiosity solutions through the use of analytically determined form-factors.
real IntegrateEdge(real3 V1, real3 V2)
{
// 'V1' and 'V2' are represented in a coordinate system with N = (0, 0, 1).
return ComputeEdgeFactor(V1, V2).z;
}
// 'sinSqSigma' is the sine^2 of the half-angle subtended by the sphere (aperture) as seen from the shaded point.
// 'cosOmega' is the cosine of the angle between the normal and the direction to the center of the light.
// N.b.: this function accounts for horizon clipping.
real DiffuseSphereLightIrradiance(real sinSqSigma, real cosOmega)
{
#ifdef APPROXIMATE_SPHERE_LIGHT_NUMERICALLY
real x = sinSqSigma;
real y = cosOmega;
// Use a numerical fit found in Mathematica. Mean absolute error: 0.00476944.
// You can use the following Mathematica code to reproduce our results:
// t = Flatten[Table[{x, y, f[x, y]}, {x, 0, 0.999999, 0.001}, {y, -0.999999, 0.999999, 0.002}], 1]
// m = NonlinearModelFit[t, x * (y + e) * (0.5 + (y - e) * (a + b * x + c * x^2 + d * x^3)), {a, b, c, d, e}, {x, y}]
return saturate(x * (0.9245867471551246 + y) * (0.5 + (-0.9245867471551246 + y) * (0.5359050373687144 + x * (-1.0054221851257754 + x * (1.8199061187417047 - x * 1.3172081704209504)))));
#else
#if 0 // Ref: Area Light Sources for Real-Time Graphics, page 4 (1996).
real sinSqOmega = saturate(1 - cosOmega * cosOmega);
real cosSqSigma = saturate(1 - sinSqSigma);
real sinSqGamma = saturate(cosSqSigma / sinSqOmega);
real cosSqGamma = saturate(1 - sinSqGamma);
real sinSigma = sqrt(sinSqSigma);
real sinGamma = sqrt(sinSqGamma);
real cosGamma = sqrt(cosSqGamma);
real sigma = asin(sinSigma);
real omega = acos(cosOmega);
real gamma = asin(sinGamma);
if (omega >= HALF_PI + sigma)
{
// Full horizon occlusion (case #4).
return 0;
}
real e = sinSqSigma * cosOmega;
UNITY_BRANCH
if (omega < HALF_PI - sigma)
{
// No horizon occlusion (case #1).
return e;
}
else
{
real g = (-2 * sqrt(sinSqOmega * cosSqSigma) + sinGamma) * cosGamma + (HALF_PI - gamma);
real h = cosOmega * (cosGamma * sqrt(saturate(sinSqSigma - cosSqGamma)) + sinSqSigma * asin(saturate(cosGamma / sinSigma)));
if (omega < HALF_PI)
{
// Partial horizon occlusion (case #2).
return saturate(e + INV_PI * (g - h));
}
else
{
// Partial horizon occlusion (case #3).
return saturate(INV_PI * (g + h));
}
}
#else // Ref: Moving Frostbite to Physically Based Rendering, page 47 (2015, optimized).
real cosSqOmega = cosOmega * cosOmega; // y^2
UNITY_BRANCH
if (cosSqOmega > sinSqSigma) // (y^2)>x
{
return saturate(sinSqSigma * cosOmega); // Clip[x*y,{0,1}]
}
else
{
real cotSqSigma = rcp(sinSqSigma) - 1; // 1/x-1
real tanSqSigma = rcp(cotSqSigma); // x/(1-x)
real sinSqOmega = 1 - cosSqOmega; // 1-y^2
real w = sinSqOmega * tanSqSigma; // (1-y^2)*(x/(1-x))
real x = -cosOmega * rsqrt(w); // -y*Sqrt[(1/x-1)/(1-y^2)]
real y = sqrt(sinSqOmega * tanSqSigma - cosSqOmega); // Sqrt[(1-y^2)*(x/(1-x))-y^2]
real z = y * cotSqSigma; // Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
real a = cosOmega * acos(x) - z; // y*ArcCos[-y*Sqrt[(1/x-1)/(1-y^2)]]-Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
real b = atan(y); // ArcTan[Sqrt[(1-y^2)*(x/(1-x))-y^2]]
return saturate(INV_PI * (a * sinSqSigma + b));
}
#endif
#endif
}
// This function does not check whether light's contribution is 0.
real3 PolygonFormFactor(real4x3 L)
{
L[0] = normalize(L[0]);
L[1] = normalize(L[1]);
L[2] = normalize(L[2]);
L[3] = normalize(L[3]);
real3 F = ComputeEdgeFactor(L[0], L[1]);
F += ComputeEdgeFactor(L[1], L[2]);
F += ComputeEdgeFactor(L[2], L[3]);
F += ComputeEdgeFactor(L[3], L[0]);
return INV_TWO_PI * F;
}
// See "Real-Time Area Lighting: a Journey from Research to Production", slide 102.
// Turns out, despite the authors claiming that this function "calculates an approximation of
// the clipped sphere form factor", that is simply not true.
// First of all, above horizon, the function should then just return 'F.z', which it does not.
// Secondly, if we use the correct function called DiffuseSphereLightIrradiance(), it results
// in severe light leaking if the light is placed vertically behind the camera.
// So this function is clearly a hack designed to work around these problems.
real PolygonIrradianceFromVectorFormFactor(float3 F)
{
#if 1
float l = length(F);
return max(0, (l * l + F.z) / (l + 1));
#else
real sff = saturate(dot(F, F));
real sinSqAperture = sqrt(sff);
real cosElevationAngle = F.z * rsqrt(sff);
return DiffuseSphereLightIrradiance(sinSqAperture, cosElevationAngle);
#endif
}
// Expects non-normalized vertex positions.
real PolygonIrradiance(real4x3 L)
{
#ifdef APPROXIMATE_POLY_LIGHT_AS_SPHERE_LIGHT
real3 F = PolygonFormFactor(L);
return PolygonIrradianceFromVectorFormFactor(F);
#else
// 1. ClipQuadToHorizon
// detect clipping config
uint config = 0;
if (L[0].z > 0) config += 1;
if (L[1].z > 0) config += 2;
if (L[2].z > 0) config += 4;
if (L[3].z > 0) config += 8;
// The fifth vertex for cases when clipping cuts off one corner.
// Due to a compiler bug, copying L into a vector array with 5 rows
// messes something up, so we need to stick with the matrix + the L4 vertex.
real3 L4 = L[3];
// This switch is surprisingly fast. Tried replacing it with a lookup array of vertices.
// Even though that replaced the switch with just some indexing and no branches, it became
// way, way slower - mem fetch stalls?
// clip
uint n = 0;
switch (config)
{
case 0: // clip all
break;
case 1: // V1 clip V2 V3 V4
n = 3;
L[1] = -L[1].z * L[0] + L[0].z * L[1];
L[2] = -L[3].z * L[0] + L[0].z * L[3];
break;
case 2: // V2 clip V1 V3 V4
n = 3;
L[0] = -L[0].z * L[1] + L[1].z * L[0];
L[2] = -L[2].z * L[1] + L[1].z * L[2];
break;
case 3: // V1 V2 clip V3 V4
n = 4;
L[2] = -L[2].z * L[1] + L[1].z * L[2];
L[3] = -L[3].z * L[0] + L[0].z * L[3];
break;
case 4: // V3 clip V1 V2 V4
n = 3;
L[0] = -L[3].z * L[2] + L[2].z * L[3];
L[1] = -L[1].z * L[2] + L[2].z * L[1];
break;
case 5: // V1 V3 clip V2 V4: impossible
break;
case 6: // V2 V3 clip V1 V4
n = 4;
L[0] = -L[0].z * L[1] + L[1].z * L[0];
L[3] = -L[3].z * L[2] + L[2].z * L[3];
break;
case 7: // V1 V2 V3 clip V4
n = 5;
L4 = -L[3].z * L[0] + L[0].z * L[3];
L[3] = -L[3].z * L[2] + L[2].z * L[3];
break;
case 8: // V4 clip V1 V2 V3
n = 3;
L[0] = -L[0].z * L[3] + L[3].z * L[0];
L[1] = -L[2].z * L[3] + L[3].z * L[2];
L[2] = L[3];
break;
case 9: // V1 V4 clip V2 V3
n = 4;
L[1] = -L[1].z * L[0] + L[0].z * L[1];
L[2] = -L[2].z * L[3] + L[3].z * L[2];
break;
case 10: // V2 V4 clip V1 V3: impossible
break;
case 11: // V1 V2 V4 clip V3
n = 5;
L[3] = -L[2].z * L[3] + L[3].z * L[2];
L[2] = -L[2].z * L[1] + L[1].z * L[2];
break;
case 12: // V3 V4 clip V1 V2
n = 4;
L[1] = -L[1].z * L[2] + L[2].z * L[1];
L[0] = -L[0].z * L[3] + L[3].z * L[0];
break;
case 13: // V1 V3 V4 clip V2
n = 5;
L[3] = L[2];
L[2] = -L[1].z * L[2] + L[2].z * L[1];
L[1] = -L[1].z * L[0] + L[0].z * L[1];
break;
case 14: // V2 V3 V4 clip V1
n = 5;
L4 = -L[0].z * L[3] + L[3].z * L[0];
L[0] = -L[0].z * L[1] + L[1].z * L[0];
break;
case 15: // V1 V2 V3 V4
n = 4;
break;
}
if (n == 0) return 0;
// 2. Project onto sphere
L[0] = normalize(L[0]);
L[1] = normalize(L[1]);
L[2] = normalize(L[2]);
switch (n)
{
case 3:
L[3] = L[0];
break;
case 4:
L[3] = normalize(L[3]);
L4 = L[0];
break;
case 5:
L[3] = normalize(L[3]);
L4 = normalize(L4);
break;
}
// 3. Integrate
real sum = 0;
sum += IntegrateEdge(L[0], L[1]);
sum += IntegrateEdge(L[1], L[2]);
sum += IntegrateEdge(L[2], L[3]);
if (n >= 4)
sum += IntegrateEdge(L[3], L4);
if (n == 5)
sum += IntegrateEdge(L4, L[0]);
sum *= INV_TWO_PI; // Normalization
sum = max(sum, 0.0);
return isfinite(sum) ? sum : 0.0;
#endif
}
real LineFpo(real tLDDL, real lrcpD, real rcpD)
{
// Compute: ((l / d) / (d * d + l * l)) + (1.0 / (d * d)) * atan(l / d).
return tLDDL + (rcpD * rcpD) * FastATan(lrcpD);
}
real LineFwt(real tLDDL, real l)
{
// Compute: l * ((l / d) / (d * d + l * l)).
return l * tLDDL;
}
// Computes the integral of the clamped cosine over the line segment.
// 'l1' and 'l2' define the integration interval.
// 'tangent' is the line's tangent direction.
// 'normal' is the direction orthogonal to the tangent. It is the shortest vector between
// the shaded point and the line, pointing away from the shaded point.
real LineIrradiance(real l1, real l2, real3 normal, real3 tangent)
{
real d = length(normal);
real l1rcpD = l1 * rcp(d);
real l2rcpD = l2 * rcp(d);
real tLDDL1 = l1rcpD / (d * d + l1 * l1);
real tLDDL2 = l2rcpD / (d * d + l2 * l2);
real intWt = LineFwt(tLDDL2, l2) - LineFwt(tLDDL1, l1);
real intP0 = LineFpo(tLDDL2, l2rcpD, rcp(d)) - LineFpo(tLDDL1, l1rcpD, rcp(d));
return intP0 * normal.z + intWt * tangent.z;
}
// Computes 1.0 / length(mul(ortho, transpose(inverse(invM)))).
real ComputeLineWidthFactor(real3x3 invM, real3 ortho)
{
// transpose(inverse(M)) = (1.0 / determinant(M)) * cofactor(M).
// Take into account that m12 = m21 = m23 = m32 = 0 and m33 = 1.
real det = invM._11 * invM._22 - invM._22 * invM._31 * invM._13;
real3x3 cof = {invM._22, 0.0, -invM._22 * invM._31,
0.0, invM._11 - invM._13 * invM._31, 0.0,
-invM._13 * invM._22, 0.0, invM._11 * invM._22};
// 1.0 / length(mul(V, (1.0 / s * M))) = abs(s) / length(mul(V, M)).
return abs(det) / length(mul(ortho, cof));
}
// For line lights.
real LTCEvaluate(real3 P1, real3 P2, real3 B, real3x3 invM)
{
real result = 0.0;
// Inverse-transform the endpoints.
P1 = mul(P1, invM);
P2 = mul(P2, invM);
// Terminate the algorithm if both points are below the horizon.
if (!(P1.z <= 0.0 && P2.z <= 0.0))
{
real width = ComputeLineWidthFactor(invM, B);
if (P1.z > P2.z)
{
// Convention: 'P2' is above 'P1', with the tangent pointing upwards.
Swap(P1, P2);
}
// Recompute the length and the tangent in the new coordinate system.
real len = length(P2 - P1);
real3 T = normalize(P2 - P1);
// Clip the part of the light below the horizon.
if (P1.z <= 0.0)
{
// P = P1 + t * T; P.z == 0.
real t = -P1.z / T.z;
P1 = real3(P1.xy + t * T.xy, 0.0);
// Set the length of the visible part of the light.
len -= t;
}
// Compute the normal direction to the line, s.t. it is the shortest vector
// between the shaded point and the line, pointing away from the shaded point.
// Can be interpreted as a point on the line, since the shaded point is at the origin.
real proj = dot(P1, T);
real3 P0 = P1 - proj * T;
// Compute the parameterization: distances from 'P1' and 'P2' to 'P0'.
real l1 = proj;
real l2 = l1 + len;
// Integrate the clamped cosine over the line segment.
real irradiance = LineIrradiance(l1, l2, P0, T);
// Guard against numerical precision issues.
result = max(INV_PI * width * irradiance, 0.0);
}
return result;
}
#endif // UNITY_AREA_LIGHTING_INCLUDED

View File

@@ -0,0 +1,175 @@
// Ref: https://github.com/knarkowicz/GPURealTimeBC6H/blob/master/bin/compress.hlsl
// Doc: https://msdn.microsoft.com/en-us/library/windows/desktop/hh308952(v=vs.85).aspx
// Measure compression error
float CalcMSLE(float3 a, float3 b)
{
float3 err = log2(( b + 1.0) / (a + 1.0 ));
err = err * err;
return err.x + err.y + err.z;
}
// Quantification Helpers
float3 Quantize7(float3 x)
{
return (f32tof16(x) * 128.0) / (0x7bff + 1.0);
}
float3 Quantize9(float3 x)
{
return (f32tof16(x) * 512.0) / (0x7bff + 1.0);
}
float3 Quantize10(float3 x)
{
return (f32tof16(x) * 1024.0) / (0x7bff + 1.0);
}
float3 Unquantize7(float3 x)
{
return (x * 65536.0 + 0x8000) / 128.0;
}
float3 Unquantize9(float3 x)
{
return (x * 65536.0 + 0x8000) / 512.0;
}
float3 Unquantize10(float3 x)
{
return (x * 65536.0 + 0x8000) / 1024.0;
}
// BC6H Helpers
// Compute index of a texel projected against endpoints
uint ComputeIndex3(float texelPos, float endPoint0Pos, float endPoint1Pos )
{
float r = ( texelPos - endPoint0Pos ) / ( endPoint1Pos - endPoint0Pos );
return (uint) clamp( r * 6.98182f + 0.00909f + 0.5f, 0.0, 7.0 );
}
uint ComputeIndex4(float texelPos, float endPoint0Pos, float endPoint1Pos )
{
float r = ( texelPos - endPoint0Pos ) / ( endPoint1Pos - endPoint0Pos );
return (uint) clamp( r * 14.93333f + 0.03333f + 0.5f, 0.0, 15.0 );
}
void SignExtend(inout float3 v1, uint mask, uint signFlag )
{
int3 v = (int3) v1;
v.x = ( v.x & mask ) | ( v.x < 0 ? signFlag : 0 );
v.y = ( v.y & mask ) | ( v.y < 0 ? signFlag : 0 );
v.z = ( v.z & mask ) | ( v.z < 0 ? signFlag : 0 );
v1 = v;
}
// 2nd step for unquantize
float3 FinishUnquantize( float3 endpoint0Unq, float3 endpoint1Unq, float weight )
{
float3 comp = ( endpoint0Unq * ( 64.0 - weight ) + endpoint1Unq * weight + 32.0 ) * ( 31.0 / 4096.0 );
return f16tof32( uint3( comp ) );
}
// BC6H Modes
void EncodeMode11( inout uint4 block, inout float blockMSLE, float3 texels[ 16 ] )
{
// compute endpoints (min/max RGB bbox)
float3 blockMin = texels[ 0 ];
float3 blockMax = texels[ 0 ];
uint i;
for (i = 1; i < 16; ++i )
{
blockMin = min( blockMin, texels[ i ] );
blockMax = max( blockMax, texels[ i ] );
}
// refine endpoints in log2 RGB space
float3 refinedBlockMin = blockMax;
float3 refinedBlockMax = blockMin;
for (i = 0; i < 16; ++i )
{
refinedBlockMin = min( refinedBlockMin, texels[ i ] == blockMin ? refinedBlockMin : texels[ i ] );
refinedBlockMax = max( refinedBlockMax, texels[ i ] == blockMax ? refinedBlockMax : texels[ i ] );
}
float3 logBlockMax = log2( blockMax + 1.0 );
float3 logBlockMin = log2( blockMin + 1.0 );
float3 logRefinedBlockMax = log2( refinedBlockMax + 1.0 );
float3 logRefinedBlockMin = log2( refinedBlockMin + 1.0 );
float3 logBlockMaxExt = ( logBlockMax - logBlockMin ) * ( 1.0 / 32.0 );
logBlockMin += min( logRefinedBlockMin - logBlockMin, logBlockMaxExt );
logBlockMax -= min( logBlockMax - logRefinedBlockMax, logBlockMaxExt );
blockMin = exp2( logBlockMin ) - 1.0;
blockMax = exp2( logBlockMax ) - 1.0;
float3 blockDir = blockMax - blockMin;
blockDir = blockDir / ( blockDir.x + blockDir.y + blockDir.z );
float3 endpoint0 = Quantize10( blockMin );
float3 endpoint1 = Quantize10( blockMax );
float endPoint0Pos = f32tof16( dot( blockMin, blockDir ) );
float endPoint1Pos = f32tof16( dot( blockMax, blockDir ) );
// check if endpoint swap is required
float fixupTexelPos = f32tof16( dot( texels[ 0 ], blockDir ) );
uint fixupIndex = ComputeIndex4( fixupTexelPos, endPoint0Pos, endPoint1Pos );
if ( fixupIndex > 7 )
{
Swap( endPoint0Pos, endPoint1Pos );
Swap( endpoint0, endpoint1 );
}
// compute indices
uint indices[ 16 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
for (i = 0; i < 16; ++i )
{
float texelPos = f32tof16( dot( texels[ i ], blockDir ) );
indices[ i ] = ComputeIndex4( texelPos, endPoint0Pos, endPoint1Pos );
}
// compute compression error (MSLE)
float3 endpoint0Unq = Unquantize10( endpoint0 );
float3 endpoint1Unq = Unquantize10( endpoint1 );
float msle = 0.0;
for (i = 0; i < 16; ++i )
{
float weight = floor( ( indices[ i ] * 64.0 ) / 15.0 + 0.5);
float3 texelUnc = FinishUnquantize( endpoint0Unq, endpoint1Unq, weight );
msle += CalcMSLE( texels[ i ], texelUnc );
}
// encode block for mode 11
blockMSLE = msle;
block.x = 0x03;
// endpoints
block.x |= (uint) endpoint0.x << 5;
block.x |= (uint) endpoint0.y << 15;
block.x |= (uint) endpoint0.z << 25;
block.y |= (uint) endpoint0.z >> 7;
block.y |= (uint) endpoint1.x << 3;
block.y |= (uint) endpoint1.y << 13;
block.y |= (uint) endpoint1.z << 23;
block.z |= (uint) endpoint1.z >> 9;
// indices
block.z |= indices[ 0 ] << 1;
block.z |= indices[ 1 ] << 4;
block.z |= indices[ 2 ] << 8;
block.z |= indices[ 3 ] << 12;
block.z |= indices[ 4 ] << 16;
block.z |= indices[ 5 ] << 20;
block.z |= indices[ 6 ] << 24;
block.z |= indices[ 7 ] << 28;
block.w |= indices[ 8 ] << 0;
block.w |= indices[ 9 ] << 4;
block.w |= indices[ 10 ] << 8;
block.w |= indices[ 11 ] << 12;
block.w |= indices[ 12 ] << 16;
block.w |= indices[ 13 ] << 20;
block.w |= indices[ 14 ] << 24;
block.w |= indices[ 15 ] << 28;
}

View File

@@ -0,0 +1,649 @@
#ifndef UNITY_BSDF_INCLUDED
#define UNITY_BSDF_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
// Note: All NDF and diffuse term have a version with and without divide by PI.
// Version with divide by PI are use for direct lighting.
// Version without divide by PI are use for image based lighting where often the PI cancel during importance sampling
//-----------------------------------------------------------------------------
// Help for BSDF evaluation
//-----------------------------------------------------------------------------
// Cosine-weighted BSDF (a BSDF taking the projected solid angle into account).
// If some of the values are monochromatic, the compiler will optimize accordingly.
struct CBSDF
{
float3 diffR; // Diffuse reflection (T -> MS -> T, same sides)
float3 specR; // Specular reflection (R, RR, TRT, etc)
float3 diffT; // Diffuse transmission (rough T or TT, opposite sides)
float3 specT; // Specular transmission (T, TT, TRRT, etc)
};
//-----------------------------------------------------------------------------
// Fresnel term
//-----------------------------------------------------------------------------
real F_Schlick(real f0, real f90, real u)
{
real x = 1.0 - u;
real x2 = x * x;
real x5 = x * x2 * x2;
return (f90 - f0) * x5 + f0; // sub mul mul mul sub mad
}
real F_Schlick(real f0, real u)
{
return F_Schlick(f0, 1.0, u); // sub mul mul mul sub mad
}
real3 F_Schlick(real3 f0, real f90, real u)
{
real x = 1.0 - u;
real x2 = x * x;
real x5 = x * x2 * x2;
return f0 * (1.0 - x5) + (f90 * x5); // sub mul mul mul sub mul mad*3
}
real3 F_Schlick(real3 f0, real u)
{
return F_Schlick(f0, 1.0, u); // sub mul mul mul sub mad*3
}
// Does not handle TIR.
real F_Transm_Schlick(real f0, real f90, real u)
{
real x = 1.0 - u;
real x2 = x * x;
real x5 = x * x2 * x2;
return (1.0 - f90 * x5) - f0 * (1.0 - x5); // sub mul mul mul mad sub mad
}
// Does not handle TIR.
real F_Transm_Schlick(real f0, real u)
{
return F_Transm_Schlick(f0, 1.0, u); // sub mul mul mad mad
}
// Does not handle TIR.
real3 F_Transm_Schlick(real3 f0, real f90, real u)
{
real x = 1.0 - u;
real x2 = x * x;
real x5 = x * x2 * x2;
return (1.0 - f90 * x5) - f0 * (1.0 - x5); // sub mul mul mul mad sub mad*3
}
// Does not handle TIR.
real3 F_Transm_Schlick(real3 f0, real u)
{
return F_Transm_Schlick(f0, 1.0, u); // sub mul mul mad mad*3
}
// Ref: https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/
// Fresnel dielectric / dielectric
real F_FresnelDielectric(real ior, real u)
{
real g = sqrt(Sq(ior) + Sq(u) - 1.0);
// The "1.0 - saturate(1.0 - result)" formulation allows to recover form cases where g is undefined, for IORs < 1
return 1.0 - saturate(1.0 - 0.5 * Sq((g - u) / (g + u)) * (1.0 + Sq(((g + u) * u - 1.0) / ((g - u) * u + 1.0))));
}
// Fresnel dieletric / conductor
// Note: etak2 = etak * etak (optimization for Artist Friendly Metallic Fresnel below)
// eta = eta_t / eta_i and etak = k_t / n_i
real3 F_FresnelConductor(real3 eta, real3 etak2, real cosTheta)
{
real cosTheta2 = cosTheta * cosTheta;
real sinTheta2 = 1.0 - cosTheta2;
real3 eta2 = eta * eta;
real3 t0 = eta2 - etak2 - sinTheta2;
real3 a2plusb2 = sqrt(t0 * t0 + 4.0 * eta2 * etak2);
real3 t1 = a2plusb2 + cosTheta2;
real3 a = sqrt(0.5 * (a2plusb2 + t0));
real3 t2 = 2.0 * a * cosTheta;
real3 Rs = (t1 - t2) / (t1 + t2);
real3 t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2;
real3 t4 = t2 * sinTheta2;
real3 Rp = Rs * (t3 - t4) / (t3 + t4);
return 0.5 * (Rp + Rs);
}
// Conversion FO/IOR
TEMPLATE_2_REAL(IorToFresnel0, transmittedIor, incidentIor, return Sq((transmittedIor - incidentIor) / (transmittedIor + incidentIor)) )
// ior is a value between 1.0 and 3.0. 1.0 is air interface
real IorToFresnel0(real transmittedIor)
{
return IorToFresnel0(transmittedIor, 1.0);
}
// Assume air interface for top
// Note: We don't handle the case fresnel0 == 1
//real Fresnel0ToIor(real fresnel0)
//{
// real sqrtF0 = sqrt(fresnel0);
// return (1.0 + sqrtF0) / (1.0 - sqrtF0);
//}
TEMPLATE_1_REAL(Fresnel0ToIor, fresnel0, return ((1.0 + sqrt(fresnel0)) / (1.0 - sqrt(fresnel0))) )
// This function is a coarse approximation of computing fresnel0 for a different top than air (here clear coat of IOR 1.5) when we only have fresnel0 with air interface
// This function is equivalent to IorToFresnel0(Fresnel0ToIor(fresnel0), 1.5)
// mean
// real sqrtF0 = sqrt(fresnel0);
// return Sq(1.0 - 5.0 * sqrtF0) / Sq(5.0 - sqrtF0);
// Optimization: Fit of the function (3 mad) for range [0.04 (should return 0), 1 (should return 1)]
TEMPLATE_1_REAL(ConvertF0ForAirInterfaceToF0ForClearCoat15, fresnel0, return saturate(-0.0256868 + fresnel0 * (0.326846 + (0.978946 - 0.283835 * fresnel0) * fresnel0)))
// Even coarser approximation of ConvertF0ForAirInterfaceToF0ForClearCoat15 (above) for mobile (2 mad)
TEMPLATE_1_REAL(ConvertF0ForAirInterfaceToF0ForClearCoat15Fast, fresnel0, return saturate(fresnel0 * (fresnel0 * 0.526868 + 0.529324) - 0.0482256))
// Artist Friendly Metallic Fresnel Ref: http://jcgt.org/published/0003/04/03/paper.pdf
real3 GetIorN(real3 f0, real3 edgeTint)
{
real3 sqrtF0 = sqrt(f0);
return lerp((1.0 - f0) / (1.0 + f0), (1.0 + sqrtF0) / (1.0 - sqrt(f0)), edgeTint);
}
real3 getIorK2(real3 f0, real3 n)
{
real3 nf0 = Sq(n + 1.0) * f0 - Sq(f0 - 1.0);
return nf0 / (1.0 - f0);
}
// same as regular refract except there is not the test for total internal reflection + the vector is flipped for processing
real3 CoatRefract(real3 X, real3 N, real ieta)
{
real XdotN = saturate(dot(N, X));
return ieta * X + (sqrt(1 + ieta * ieta * (XdotN * XdotN - 1)) - ieta * XdotN) * N;
}
//-----------------------------------------------------------------------------
// Specular BRDF
//-----------------------------------------------------------------------------
float Lambda_GGX(float roughness, float3 V)
{
return 0.5 * (sqrt(1.0 + (Sq(roughness * V.x) + Sq(roughness * V.y)) / Sq(V.z)) - 1.0);
}
real D_GGXNoPI(real NdotH, real roughness)
{
real a2 = Sq(roughness);
real s = (NdotH * a2 - NdotH) * NdotH + 1.0;
// If roughness is 0, returns (NdotH == 1 ? 1 : 0).
// That is, it returns 1 for perfect mirror reflection, and 0 otherwise.
return SafeDiv(a2, s * s);
}
real D_GGX(real NdotH, real roughness)
{
return INV_PI * D_GGXNoPI(NdotH, roughness);
}
// Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, p. 19, 29.
// p. 84 (37/60)
real G_MaskingSmithGGX(real NdotV, real roughness)
{
// G1(V, H) = HeavisideStep(VdotH) / (1 + Lambda(V)).
// Lambda(V) = -0.5 + 0.5 * sqrt(1 + 1 / a^2).
// a = 1 / (roughness * tan(theta)).
// 1 + Lambda(V) = 0.5 + 0.5 * sqrt(1 + roughness^2 * tan^2(theta)).
// tan^2(theta) = (1 - cos^2(theta)) / cos^2(theta) = 1 / cos^2(theta) - 1.
// Assume that (VdotH > 0), e.i. (acos(LdotV) < Pi).
return 1.0 / (0.5 + 0.5 * sqrt(1.0 + Sq(roughness) * (1.0 / Sq(NdotV) - 1.0)));
}
// Precompute part of lambdaV
real GetSmithJointGGXPartLambdaV(real NdotV, real roughness)
{
real a2 = Sq(roughness);
return sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
}
// Note: V = G / (4 * NdotL * NdotV)
// Ref: http://jcgt.org/published/0003/02/03/paper.pdf
real V_SmithJointGGX(real NdotL, real NdotV, real roughness, real partLambdaV)
{
real a2 = Sq(roughness);
// Original formulation:
// lambda_v = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5
// lambda_l = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5
// G = 1 / (1 + lambda_v + lambda_l);
// Reorder code to be more optimal:
real lambdaV = NdotL * partLambdaV;
real lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
// Simplify visibility term: (2.0 * NdotL * NdotV) / ((4.0 * NdotL * NdotV) * (lambda_v + lambda_l))
return 0.5 / max(lambdaV + lambdaL, REAL_MIN);
}
real V_SmithJointGGX(real NdotL, real NdotV, real roughness)
{
real partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
return V_SmithJointGGX(NdotL, NdotV, roughness, partLambdaV);
}
// Inline D_GGX() * V_SmithJointGGX() together for better code generation.
real DV_SmithJointGGX(real NdotH, real NdotL, real NdotV, real roughness, real partLambdaV)
{
real a2 = Sq(roughness);
real s = (NdotH * a2 - NdotH) * NdotH + 1.0;
real lambdaV = NdotL * partLambdaV;
real lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
real2 D = real2(a2, s * s); // Fraction without the multiplier (1/Pi)
real2 G = real2(1, lambdaV + lambdaL); // Fraction without the multiplier (1/2)
// This function is only used for direct lighting.
// If roughness is 0, the probability of hitting a punctual or directional light is also 0.
// Therefore, we return 0. The most efficient way to do it is with a max().
return INV_PI * 0.5 * (D.x * G.x) / max(D.y * G.y, REAL_MIN);
}
real DV_SmithJointGGX(real NdotH, real NdotL, real NdotV, real roughness)
{
real partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
return DV_SmithJointGGX(NdotH, NdotL, NdotV, roughness, partLambdaV);
}
// Precompute a part of LambdaV.
// Note on this linear approximation.
// Exact for roughness values of 0 and 1. Also, exact when the cosine is 0 or 1.
// Otherwise, the worst case relative error is around 10%.
// https://www.desmos.com/calculator/wtp8lnjutx
real GetSmithJointGGXPartLambdaVApprox(real NdotV, real roughness)
{
real a = roughness;
return NdotV * (1 - a) + a;
}
real V_SmithJointGGXApprox(real NdotL, real NdotV, real roughness, real partLambdaV)
{
real a = roughness;
real lambdaV = NdotL * partLambdaV;
real lambdaL = NdotV * (NdotL * (1 - a) + a);
return 0.5 / (lambdaV + lambdaL);
}
real V_SmithJointGGXApprox(real NdotL, real NdotV, real roughness)
{
real partLambdaV = GetSmithJointGGXPartLambdaVApprox(NdotV, roughness);
return V_SmithJointGGXApprox(NdotL, NdotV, roughness, partLambdaV);
}
// roughnessT -> roughness in tangent direction
// roughnessB -> roughness in bitangent direction
real D_GGXAnisoNoPI(real TdotH, real BdotH, real NdotH, real roughnessT, real roughnessB)
{
real a2 = roughnessT * roughnessB;
real3 v = real3(roughnessB * TdotH, roughnessT * BdotH, a2 * NdotH);
real s = dot(v, v);
// If roughness is 0, returns (NdotH == 1 ? 1 : 0).
// That is, it returns 1 for perfect mirror reflection, and 0 otherwise.
return SafeDiv(a2 * a2 * a2, s * s);
}
real D_GGXAniso(real TdotH, real BdotH, real NdotH, real roughnessT, real roughnessB)
{
return INV_PI * D_GGXAnisoNoPI(TdotH, BdotH, NdotH, roughnessT, roughnessB);
}
real GetSmithJointGGXAnisoPartLambdaV(real TdotV, real BdotV, real NdotV, real roughnessT, real roughnessB)
{
return length(real3(roughnessT * TdotV, roughnessB * BdotV, NdotV));
}
// Note: V = G / (4 * NdotL * NdotV)
// Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4
real V_SmithJointGGXAniso(real TdotV, real BdotV, real NdotV, real TdotL, real BdotL, real NdotL, real roughnessT, real roughnessB, real partLambdaV)
{
real lambdaV = NdotL * partLambdaV;
real lambdaL = NdotV * length(real3(roughnessT * TdotL, roughnessB * BdotL, NdotL));
return 0.5 / (lambdaV + lambdaL);
}
real V_SmithJointGGXAniso(real TdotV, real BdotV, real NdotV, real TdotL, real BdotL, real NdotL, real roughnessT, real roughnessB)
{
real partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB);
return V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB, partLambdaV);
}
// Inline D_GGXAniso() * V_SmithJointGGXAniso() together for better code generation.
real DV_SmithJointGGXAniso(real TdotH, real BdotH, real NdotH, real NdotV,
real TdotL, real BdotL, real NdotL,
real roughnessT, real roughnessB, real partLambdaV)
{
real a2 = roughnessT * roughnessB;
real3 v = real3(roughnessB * TdotH, roughnessT * BdotH, a2 * NdotH);
real s = dot(v, v);
real lambdaV = NdotL * partLambdaV;
real lambdaL = NdotV * length(real3(roughnessT * TdotL, roughnessB * BdotL, NdotL));
real2 D = real2(a2 * a2 * a2, s * s); // Fraction without the multiplier (1/Pi)
real2 G = real2(1, lambdaV + lambdaL); // Fraction without the multiplier (1/2)
// This function is only used for direct lighting.
// If roughness is 0, the probability of hitting a punctual or directional light is also 0.
// Therefore, we return 0. The most efficient way to do it is with a max().
return (INV_PI * 0.5) * (D.x * G.x) / max(D.y * G.y, REAL_MIN);
}
real DV_SmithJointGGXAniso(real TdotH, real BdotH, real NdotH,
real TdotV, real BdotV, real NdotV,
real TdotL, real BdotL, real NdotL,
real roughnessT, real roughnessB)
{
real partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB);
return DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV,
TdotL, BdotL, NdotL,
roughnessT, roughnessB, partLambdaV);
}
// Get projected roughness for a certain normalized direction V in tangent space
// and an anisotropic roughness
// Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, Heitz 2014, pp. 86, 88 - 39/60, 41/60
float GetProjectedRoughness(float TdotV, float BdotV, float NdotV, float roughnessT, float roughnessB)
{
float2 roughness = float2(roughnessT, roughnessB);
float sinTheta2 = max((1 - Sq(NdotV)), FLT_MIN);
// if sinTheta^2 = 0, NdotV = 1, TdotV = BdotV = 0 and roughness is arbitrary, no real azimuth
// as there's a breakdown of the spherical parameterization, so we clamp under by FLT_MIN in any case
// for safe division
// Note:
// sin(thetaV)^2 * cos(phiV)^2 = (TdotV)^2
// sin(thetaV)^2 * sin(phiV)^2 = (BdotV)^2
float2 vProj2 = Sq(float2(TdotV, BdotV)) * rcp(sinTheta2);
// vProj2 = (cos^2(phi), sin^2(phi))
float projRoughness = sqrt(dot(vProj2, roughness*roughness));
return projRoughness;
}
//-----------------------------------------------------------------------------
// Diffuse BRDF - diffuseColor is expected to be multiply by the caller
//-----------------------------------------------------------------------------
real LambertNoPI()
{
return 1.0;
}
real Lambert()
{
return INV_PI;
}
real DisneyDiffuseNoPI(real NdotV, real NdotL, real LdotV, real perceptualRoughness)
{
// (2 * LdotH * LdotH) = 1 + LdotV
// real fd90 = 0.5 + (2 * LdotH * LdotH) * perceptualRoughness;
real fd90 = 0.5 + (perceptualRoughness + perceptualRoughness * LdotV);
// Two schlick fresnel term
real lightScatter = F_Schlick(1.0, fd90, NdotL);
real viewScatter = F_Schlick(1.0, fd90, NdotV);
// Normalize the BRDF for polar view angles of up to (Pi/4).
// We use the worst case of (roughness = albedo = 1), and, for each view angle,
// integrate (brdf * cos(theta_light)) over all light directions.
// The resulting value is for (theta_view = 0), which is actually a little bit larger
// than the value of the integral for (theta_view = Pi/4).
// Hopefully, the compiler folds the constant together with (1/Pi).
return rcp(1.03571) * (lightScatter * viewScatter);
}
real DisneyDiffuse(real NdotV, real NdotL, real LdotV, real perceptualRoughness)
{
return INV_PI * DisneyDiffuseNoPI(NdotV, NdotL, LdotV, perceptualRoughness);
}
// Ref: Diffuse Lighting for GGX + Smith Microsurfaces, p. 113.
real3 DiffuseGGXNoPI(real3 albedo, real NdotV, real NdotL, real NdotH, real LdotV, real roughness)
{
real facing = 0.5 + 0.5 * LdotV; // (LdotH)^2
real rough = facing * (0.9 - 0.4 * facing) * (0.5 / NdotH + 1);
real transmitL = F_Transm_Schlick(0, NdotL);
real transmitV = F_Transm_Schlick(0, NdotV);
real smooth = transmitL * transmitV * 1.05; // Normalize F_t over the hemisphere
real single = lerp(smooth, rough, roughness); // Rescaled by PI
real multiple = roughness * (0.1159 * PI); // Rescaled by PI
return single + albedo * multiple;
}
real3 DiffuseGGX(real3 albedo, real NdotV, real NdotL, real NdotH, real LdotV, real roughness)
{
// Note that we could save 2 cycles by inlining the multiplication by INV_PI.
return INV_PI * DiffuseGGXNoPI(albedo, NdotV, NdotL, NdotH, LdotV, roughness);
}
//-----------------------------------------------------------------------------
// Iridescence
//-----------------------------------------------------------------------------
// Ref: https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html
// Evaluation XYZ sensitivity curves in Fourier space
real3 EvalSensitivity(real opd, real shift)
{
// Use Gaussian fits, given by 3 parameters: val, pos and var
real phase = 2.0 * PI * opd * 1e-6;
real3 val = real3(5.4856e-13, 4.4201e-13, 5.2481e-13);
real3 pos = real3(1.6810e+06, 1.7953e+06, 2.2084e+06);
real3 var = real3(4.3278e+09, 9.3046e+09, 6.6121e+09);
real3 xyz = val * sqrt(2.0 * PI * var) * cos(pos * phase + shift) * exp(-var * phase * phase);
xyz.x += 9.7470e-14 * sqrt(2.0 * PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift) * exp(-4.5282e+09 * phase * phase);
xyz /= 1.0685e-7;
// Convert to linear sRGb color space here.
// EvalIridescence works in linear sRGB color space and does not switch...
real3 srgb = mul(XYZ_2_REC709_MAT, xyz);
return srgb;
}
// Evaluate the reflectance for a thin-film layer on top of a dielectric medum.
real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, real3 baseLayerFresnel0, real iorOverBaseLayer = 0.0)
{
real3 I;
// iridescenceThickness unit is micrometer for this equation here. Mean 0.5 is 500nm.
real Dinc = 3.0 * iridescenceThickness;
// Note: Unlike the code provide with the paper, here we use schlick approximation
// Schlick is a very poor approximation when dealing with iridescence to the Fresnel
// term and there is no "neutral" value in this unlike in the original paper.
// We use Iridescence mask here to allow to have neutral value
// Hack: In order to use only one parameter (DInc), we deduced the ior of iridescence from current Dinc iridescenceThickness
// and we use mask instead to fade out the effect
real eta_2 = lerp(2.0, 1.0, iridescenceThickness);
// Following line from original code is not needed for us, it create a discontinuity
// Force eta_2 -> eta_1 when Dinc -> 0.0
// real eta_2 = lerp(eta_1, eta_2, smoothstep(0.0, 0.03, Dinc));
// Evaluate the cosTheta on the base layer (Snell law)
real sinTheta2Sq = Sq(eta_1 / eta_2) * (1.0 - Sq(cosTheta1));
// Handle TIR:
// (Also note that with just testing sinTheta2Sq > 1.0, (1.0 - sinTheta2Sq) can be negative, as emitted instructions
// can eg be a mad giving a small negative for (1.0 - sinTheta2Sq), while sinTheta2Sq still testing equal to 1.0), so we actually
// test the operand [cosTheta2Sq := (1.0 - sinTheta2Sq)] < 0 directly:)
real cosTheta2Sq = (1.0 - sinTheta2Sq);
// Or use this "artistic hack" to get more continuity even though wrong (no TIR, continue the effect by mirroring it):
// if( cosTheta2Sq < 0.0 ) => { sinTheta2Sq = 2 - sinTheta2Sq; => so cosTheta2Sq = sinTheta2Sq - 1 }
// ie don't test and simply do
// real cosTheta2Sq = abs(1.0 - sinTheta2Sq);
if (cosTheta2Sq < 0.0)
I = real3(1.0, 1.0, 1.0);
else
{
real cosTheta2 = sqrt(cosTheta2Sq);
// First interface
real R0 = IorToFresnel0(eta_2, eta_1);
real R12 = F_Schlick(R0, cosTheta1);
real R21 = R12;
real T121 = 1.0 - R12;
real phi12 = 0.0;
real phi21 = PI - phi12;
// Second interface
// The f0 or the base should account for the new computed eta_2 on top.
// This is optionally done if we are given the needed current ior over the base layer that is accounted for
// in the baseLayerFresnel0 parameter:
if (iorOverBaseLayer > 0.0)
{
// Fresnel0ToIor will give us a ratio of baseIor/topIor, hence we * iorOverBaseLayer to get the baseIor
real3 baseIor = iorOverBaseLayer * Fresnel0ToIor(baseLayerFresnel0 + 0.0001); // guard against 1.0
baseLayerFresnel0 = IorToFresnel0(baseIor, eta_2);
}
real3 R23 = F_Schlick(baseLayerFresnel0, cosTheta2);
real phi23 = 0.0;
// Phase shift
real OPD = Dinc * cosTheta2;
real phi = phi21 + phi23;
// Compound terms
real3 R123 = clamp(R12 * R23, 1e-5, 0.9999);
real3 r123 = sqrt(R123);
real3 Rs = Sq(T121) * R23 / (real3(1.0, 1.0, 1.0) - R123);
// Reflectance term for m = 0 (DC term amplitude)
real3 C0 = R12 + Rs;
I = C0;
// Reflectance term for m > 0 (pairs of diracs)
real3 Cm = Rs - T121;
for (int m = 1; m <= 2; ++m)
{
Cm *= r123;
real3 Sm = 2.0 * EvalSensitivity(m * OPD, m * phi);
//vec3 SmP = 2.0 * evalSensitivity(m*OPD, m*phi2.y);
I += Cm * Sm;
}
// Since out of gamut colors might be produced, negative color values are clamped to 0.
I = max(I, float3(0.0, 0.0, 0.0));
}
return I;
}
//-----------------------------------------------------------------------------
// Fabric
//-----------------------------------------------------------------------------
// Ref: https://knarkowicz.wordpress.com/2018/01/04/cloth-shading/
real D_CharlieNoPI(real NdotH, real roughness)
{
float invR = rcp(roughness);
float cos2h = NdotH * NdotH;
float sin2h = 1.0 - cos2h;
// Note: We have sin^2 so multiply by 0.5 to cancel it
return (2.0 + invR) * PositivePow(sin2h, invR * 0.5) / 2.0;
}
real D_Charlie(real NdotH, real roughness)
{
return INV_PI * D_CharlieNoPI(NdotH, roughness);
}
real CharlieL(real x, real r)
{
r = saturate(r);
r = 1.0 - (1.0 - r) * (1.0 - r);
float a = lerp(25.3245, 21.5473, r);
float b = lerp(3.32435, 3.82987, r);
float c = lerp(0.16801, 0.19823, r);
float d = lerp(-1.27393, -1.97760, r);
float e = lerp(-4.85967, -4.32054, r);
return a / (1. + b * PositivePow(x, c)) + d * x + e;
}
// Note: This version don't include the softening of the paper: Production Friendly Microfacet Sheen BRDF
real V_Charlie(real NdotL, real NdotV, real roughness)
{
real lambdaV = NdotV < 0.5 ? exp(CharlieL(NdotV, roughness)) : exp(2.0 * CharlieL(0.5, roughness) - CharlieL(1.0 - NdotV, roughness));
real lambdaL = NdotL < 0.5 ? exp(CharlieL(NdotL, roughness)) : exp(2.0 * CharlieL(0.5, roughness) - CharlieL(1.0 - NdotL, roughness));
return 1.0 / ((1.0 + lambdaV + lambdaL) * (4.0 * NdotV * NdotL));
}
// We use V_Ashikhmin instead of V_Charlie in practice for game due to the cost of V_Charlie
real V_Ashikhmin(real NdotL, real NdotV)
{
// Use soft visibility term introduce in: Crafting a Next-Gen Material Pipeline for The Order : 1886
return 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV));
}
// A diffuse term use with fabric done by tech artist - empirical
real FabricLambertNoPI(real roughness)
{
return lerp(1.0, 0.5, roughness);
}
real FabricLambert(real roughness)
{
return INV_PI * FabricLambertNoPI(roughness);
}
real G_CookTorrance(real NdotH, real NdotV, real NdotL, real HdotV)
{
return min(1.0, 2.0 * NdotH * min(NdotV, NdotL) / HdotV);
}
//-----------------------------------------------------------------------------
// Hair
//-----------------------------------------------------------------------------
//http://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf
real3 ShiftTangent(real3 T, real3 N, real shift)
{
return normalize(T + N * shift);
}
// Note: this is Blinn-Phong, the original paper uses Phong.
real3 D_KajiyaKay(real3 T, real3 H, real specularExponent)
{
real TdotH = dot(T, H);
real sinTHSq = saturate(1.0 - TdotH * TdotH);
real dirAttn = saturate(TdotH + 1.0); // Evgenii: this seems like a hack? Do we really need this?
// Note: Kajiya-Kay is not energy conserving.
// We attempt at least some energy conservation by approximately normalizing Blinn-Phong NDF.
// We use the formulation with the NdotL.
// See http://www.thetenthplanet.de/archives/255.
real n = specularExponent;
real norm = (n + 2) * rcp(2 * PI);
return dirAttn * norm * PositivePow(sinTHSq, 0.5 * n);
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_BSDF_INCLUDED

View File

@@ -0,0 +1,742 @@
#ifndef UNITY_COLOR_INCLUDED
#define UNITY_COLOR_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl"
//-----------------------------------------------------------------------------
// Gamma space - Assume positive values
//-----------------------------------------------------------------------------
// Gamma20
real Gamma20ToLinear(real c)
{
return c * c;
}
real3 Gamma20ToLinear(real3 c)
{
return c.rgb * c.rgb;
}
real4 Gamma20ToLinear(real4 c)
{
return real4(Gamma20ToLinear(c.rgb), c.a);
}
real LinearToGamma20(real c)
{
return sqrt(c);
}
real3 LinearToGamma20(real3 c)
{
return sqrt(c.rgb);
}
real4 LinearToGamma20(real4 c)
{
return real4(LinearToGamma20(c.rgb), c.a);
}
// Gamma22
real Gamma22ToLinear(real c)
{
return PositivePow(c, 2.2);
}
real3 Gamma22ToLinear(real3 c)
{
return PositivePow(c.rgb, real3(2.2, 2.2, 2.2));
}
real4 Gamma22ToLinear(real4 c)
{
return real4(Gamma22ToLinear(c.rgb), c.a);
}
real LinearToGamma22(real c)
{
return PositivePow(c, 0.454545454545455);
}
real3 LinearToGamma22(real3 c)
{
return PositivePow(c.rgb, real3(0.454545454545455, 0.454545454545455, 0.454545454545455));
}
real4 LinearToGamma22(real4 c)
{
return real4(LinearToGamma22(c.rgb), c.a);
}
// sRGB
real SRGBToLinear(real c)
{
real linearRGBLo = c / 12.92;
real linearRGBHi = PositivePow((c + 0.055) / 1.055, 2.4);
real linearRGB = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
return linearRGB;
}
real2 SRGBToLinear(real2 c)
{
real2 linearRGBLo = c / 12.92;
real2 linearRGBHi = PositivePow((c + 0.055) / 1.055, real2(2.4, 2.4));
real2 linearRGB = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
return linearRGB;
}
real3 SRGBToLinear(real3 c)
{
real3 linearRGBLo = c / 12.92;
real3 linearRGBHi = PositivePow((c + 0.055) / 1.055, real3(2.4, 2.4, 2.4));
real3 linearRGB = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
return linearRGB;
}
real4 SRGBToLinear(real4 c)
{
return real4(SRGBToLinear(c.rgb), c.a);
}
real LinearToSRGB(real c)
{
real sRGBLo = c * 12.92;
real sRGBHi = (PositivePow(c, 1.0/2.4) * 1.055) - 0.055;
real sRGB = (c <= 0.0031308) ? sRGBLo : sRGBHi;
return sRGB;
}
real2 LinearToSRGB(real2 c)
{
real2 sRGBLo = c * 12.92;
real2 sRGBHi = (PositivePow(c, real2(1.0/2.4, 1.0/2.4)) * 1.055) - 0.055;
real2 sRGB = (c <= 0.0031308) ? sRGBLo : sRGBHi;
return sRGB;
}
real3 LinearToSRGB(real3 c)
{
real3 sRGBLo = c * 12.92;
real3 sRGBHi = (PositivePow(c, real3(1.0/2.4, 1.0/2.4, 1.0/2.4)) * 1.055) - 0.055;
real3 sRGB = (c <= 0.0031308) ? sRGBLo : sRGBHi;
return sRGB;
}
real4 LinearToSRGB(real4 c)
{
return real4(LinearToSRGB(c.rgb), c.a);
}
// TODO: Seb - To verify and refit!
// Ref: http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
real FastSRGBToLinear(real c)
{
return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
}
real2 FastSRGBToLinear(real2 c)
{
return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
}
real3 FastSRGBToLinear(real3 c)
{
return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
}
real4 FastSRGBToLinear(real4 c)
{
return real4(FastSRGBToLinear(c.rgb), c.a);
}
real FastLinearToSRGB(real c)
{
return saturate(1.055 * PositivePow(c, 0.416666667) - 0.055);
}
real2 FastLinearToSRGB(real2 c)
{
return saturate(1.055 * PositivePow(c, 0.416666667) - 0.055);
}
real3 FastLinearToSRGB(real3 c)
{
return saturate(1.055 * PositivePow(c, 0.416666667) - 0.055);
}
real4 FastLinearToSRGB(real4 c)
{
return real4(FastLinearToSRGB(c.rgb), c.a);
}
//-----------------------------------------------------------------------------
// Color space
//-----------------------------------------------------------------------------
// Convert rgb to luminance
// with rgb in linear space with sRGB primaries and D65 white point
real Luminance(real3 linearRgb)
{
return dot(linearRgb, real3(0.2126729, 0.7151522, 0.0721750));
}
real Luminance(real4 linearRgba)
{
return Luminance(linearRgba.rgb);
}
real AcesLuminance(real3 linearRgb)
{
return dot(linearRgb, AP1_RGB2Y);
}
real AcesLuminance(real4 linearRgba)
{
return AcesLuminance(linearRgba.rgb);
}
// Scotopic luminance approximation - input is in XYZ space
// Note: the range of values returned is approximately [0;4]
// "A spatial postprocessing algorithm for images of night scenes"
// William B. Thompson, Peter Shirley, and James A. Ferwerda
real ScotopicLuminance(real3 xyzRgb)
{
float X = xyzRgb.x;
float Y = xyzRgb.y;
float Z = xyzRgb.z;
return Y * (1.33 * (1.0 + (Y + Z) / X) - 1.68);
}
real ScotopicLuminance(real4 xyzRgba)
{
return ScotopicLuminance(xyzRgba.rgb);
}
// This function take a rgb color (best is to provide color in sRGB space)
// and return a YCoCg color in [0..1] space for 8bit (An offset is apply in the function)
// Ref: http://www.nvidia.com/object/real-time-ycocg-dxt-compression.html
#define YCOCG_CHROMA_BIAS (128.0 / 255.0)
real3 RGBToYCoCg(real3 rgb)
{
real3 YCoCg;
YCoCg.x = dot(rgb, real3(0.25, 0.5, 0.25));
YCoCg.y = dot(rgb, real3(0.5, 0.0, -0.5)) + YCOCG_CHROMA_BIAS;
YCoCg.z = dot(rgb, real3(-0.25, 0.5, -0.25)) + YCOCG_CHROMA_BIAS;
return YCoCg;
}
real3 YCoCgToRGB(real3 YCoCg)
{
real Y = YCoCg.x;
real Co = YCoCg.y - YCOCG_CHROMA_BIAS;
real Cg = YCoCg.z - YCOCG_CHROMA_BIAS;
real3 rgb;
rgb.r = Y + Co - Cg;
rgb.g = Y + Cg;
rgb.b = Y - Co - Cg;
return rgb;
}
// Following function can be use to reconstruct chroma component for a checkboard YCoCg pattern
// Reference: The Compact YCoCg Frame Buffer
real YCoCgCheckBoardEdgeFilter(real centerLum, real2 a0, real2 a1, real2 a2, real2 a3)
{
real4 lum = real4(a0.x, a1.x, a2.x, a3.x);
// Optimize: real4 w = 1.0 - step(30.0 / 255.0, abs(lum - centerLum));
real4 w = 1.0 - saturate((abs(lum.xxxx - centerLum) - 30.0 / 255.0) * HALF_MAX);
real W = w.x + w.y + w.z + w.w;
// handle the special case where all the weights are zero.
return (W == 0.0) ? a0.y : (w.x * a0.y + w.y* a1.y + w.z* a2.y + w.w * a3.y) / W;
}
// Converts linear RGB to LMS
float3 LinearToLMS(float3 x) // Full float precision to avoid precision artefact when using ACES tonemapping
{
const real3x3 LIN_2_LMS_MAT = {
3.90405e-1, 5.49941e-1, 8.92632e-3,
7.08416e-2, 9.63172e-1, 1.35775e-3,
2.31082e-2, 1.28021e-1, 9.36245e-1
};
return mul(LIN_2_LMS_MAT, x);
}
float3 LMSToLinear(float3 x) // Full float precision to avoid precision artefact when using ACES tonemapping
{
const real3x3 LMS_2_LIN_MAT = {
2.85847e+0, -1.62879e+0, -2.48910e-2,
-2.10182e-1, 1.15820e+0, 3.24281e-4,
-4.18120e-2, -1.18169e-1, 1.06867e+0
};
return mul(LMS_2_LIN_MAT, x);
}
// Hue, Saturation, Value
// Ranges:
// Hue [0.0, 1.0]
// Sat [0.0, 1.0]
// Lum [0.0, HALF_MAX]
real3 RgbToHsv(real3 c)
{
const real4 K = real4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
real4 p = lerp(real4(c.bg, K.wz), real4(c.gb, K.xy), step(c.b, c.g));
real4 q = lerp(real4(p.xyw, c.r), real4(c.r, p.yzx), step(p.x, c.r));
real d = q.x - min(q.w, q.y);
const real e = 1.0e-4;
return real3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
real3 HsvToRgb(real3 c)
{
const real4 K = real4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
real3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
real RotateHue(real value, real low, real hi)
{
return (value < low)
? value + hi
: (value > hi)
? value - hi
: value;
}
// Soft-light blending mode use for split-toning. Works in HDR as long as `blend` is [0;1] which is
// fine for our use case.
float3 SoftLight(float3 base, float3 blend)
{
float3 r1 = 2.0 * base * blend + base * base * (1.0 - 2.0 * blend);
float3 r2 = sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend);
float3 t = step(0.5, blend);
return r2 * t + (1.0 - t) * r1;
}
// SMPTE ST.2084 (PQ) transfer functions
// 1.0 = 100nits, 100.0 = 10knits
#define DEFAULT_MAX_PQ 100.0
struct ParamsPQ
{
real N, M;
real C1, C2, C3;
};
static const ParamsPQ PQ =
{
2610.0 / 4096.0 / 4.0, // N
2523.0 / 4096.0 * 128.0, // M
3424.0 / 4096.0, // C1
2413.0 / 4096.0 * 32.0, // C2
2392.0 / 4096.0 * 32.0, // C3
};
real3 LinearToPQ(real3 x, real maxPQValue)
{
x = PositivePow(x / maxPQValue, PQ.N);
real3 nd = (PQ.C1 + PQ.C2 * x) / (1.0 + PQ.C3 * x);
return PositivePow(nd, PQ.M);
}
real3 LinearToPQ(real3 x)
{
return LinearToPQ(x, DEFAULT_MAX_PQ);
}
real3 PQToLinear(real3 x, real maxPQValue)
{
x = PositivePow(x, rcp(PQ.M));
real3 nd = max(x - PQ.C1, 0.0) / (PQ.C2 - (PQ.C3 * x));
return PositivePow(nd, rcp(PQ.N)) * maxPQValue;
}
real3 PQToLinear(real3 x)
{
return PQToLinear(x, DEFAULT_MAX_PQ);
}
// Alexa LogC converters (El 1000)
// See http://www.vocas.nl/webfm_send/964
// Max range is ~58.85666
// Set to 1 to use more precise but more expensive log/linear conversions. I haven't found a proper
// use case for the high precision version yet so I'm leaving this to 0.
#define USE_PRECISE_LOGC 0
struct ParamsLogC
{
real cut;
real a, b, c, d, e, f;
};
static const ParamsLogC LogC =
{
0.011361, // cut
5.555556, // a
0.047996, // b
0.244161, // c
0.386036, // d
5.301883, // e
0.092819 // f
};
real LinearToLogC_Precise(real x)
{
real o;
if (x > LogC.cut)
o = LogC.c * log10(max(LogC.a * x + LogC.b, 0.0)) + LogC.d;
else
o = LogC.e * x + LogC.f;
return o;
}
float3 LinearToLogC(float3 x) // Full float precision to avoid precision artefact when using ACES tonemapping
{
#if USE_PRECISE_LOGC
return real3(
LinearToLogC_Precise(x.x),
LinearToLogC_Precise(x.y),
LinearToLogC_Precise(x.z)
);
#else
return LogC.c * log10(max(LogC.a * x + LogC.b, 0.0)) + LogC.d;
#endif
}
real LogCToLinear_Precise(real x)
{
real o;
if (x > LogC.e * LogC.cut + LogC.f)
o = (pow(10.0, (x - LogC.d) / LogC.c) - LogC.b) / LogC.a;
else
o = (x - LogC.f) / LogC.e;
return o;
}
float3 LogCToLinear(float3 x) // Full float precision to avoid precision artefact when using ACES tonemapping
{
#if USE_PRECISE_LOGC
return real3(
LogCToLinear_Precise(x.x),
LogCToLinear_Precise(x.y),
LogCToLinear_Precise(x.z)
);
#else
return (pow(10.0, (x - LogC.d) / LogC.c) - LogC.b) / LogC.a;
#endif
}
//-----------------------------------------------------------------------------
// Utilities
//-----------------------------------------------------------------------------
real3 Desaturate(real3 value, real saturation)
{
// Saturation = Colorfulness / Brightness.
// https://munsell.com/color-blog/difference-chroma-saturation/
real mean = Avg3(value.r, value.g, value.b);
real3 dev = value - mean;
return mean + dev * saturation;
}
// Fast reversible tonemapper
// http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
real FastTonemapPerChannel(real c)
{
return c * rcp(c + 1.0);
}
real2 FastTonemapPerChannel(real2 c)
{
return c * rcp(c + 1.0);
}
real3 FastTonemap(real3 c)
{
return c * rcp(Max3(c.r, c.g, c.b) + 1.0);
}
real4 FastTonemap(real4 c)
{
return real4(FastTonemap(c.rgb), c.a);
}
real3 FastTonemap(real3 c, real w)
{
return c * (w * rcp(Max3(c.r, c.g, c.b) + 1.0));
}
real4 FastTonemap(real4 c, real w)
{
return real4(FastTonemap(c.rgb, w), c.a);
}
real FastTonemapPerChannelInvert(real c)
{
return c * rcp(1.0 - c);
}
real2 FastTonemapPerChannelInvert(real2 c)
{
return c * rcp(1.0 - c);
}
real3 FastTonemapInvert(real3 c)
{
return c * rcp(1.0 - Max3(c.r, c.g, c.b));
}
real4 FastTonemapInvert(real4 c)
{
return real4(FastTonemapInvert(c.rgb), c.a);
}
#ifndef SHADER_API_GLES
// 3D LUT grading
// scaleOffset = (1 / lut_size, lut_size - 1)
real3 ApplyLut3D(TEXTURE3D_PARAM(tex, samplerTex), float3 uvw, float2 scaleOffset)
{
uvw.xyz = uvw.xyz * scaleOffset.yyy * scaleOffset.xxx + scaleOffset.xxx * 0.5;
return SAMPLE_TEXTURE3D_LOD(tex, samplerTex, uvw, 0.0).rgb;
}
#endif
// 2D LUT grading
// scaleOffset = (1 / lut_width, 1 / lut_height, lut_height - 1)
real3 ApplyLut2D(TEXTURE2D_PARAM(tex, samplerTex), float3 uvw, float3 scaleOffset)
{
// Strip format where `height = sqrt(width)`
uvw.z *= scaleOffset.z;
float shift = floor(uvw.z);
uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5;
uvw.x += shift * scaleOffset.y;
uvw.xyz = lerp(
SAMPLE_TEXTURE2D_LOD(tex, samplerTex, uvw.xy, 0.0).rgb,
SAMPLE_TEXTURE2D_LOD(tex, samplerTex, uvw.xy + float2(scaleOffset.y, 0.0), 0.0).rgb,
uvw.z - shift
);
return uvw;
}
// Returns the default value for a given position on a 2D strip-format color lookup table
// params = (lut_height, 0.5 / lut_width, 0.5 / lut_height, lut_height / lut_height - 1)
real3 GetLutStripValue(float2 uv, float4 params)
{
uv -= params.yz;
real3 color;
color.r = frac(uv.x * params.x);
color.b = uv.x - color.r / params.x;
color.g = uv.y;
return color * params.w;
}
// Neutral tonemapping (Hable/Hejl/Frostbite)
// Input is linear RGB
#if defined(SHADER_API_SWITCH) // We need more accuracy on Nintendo Switch to avoid NaN on extremely high values.
float3 NeutralCurve(float3 x, real a, real b, real c, real d, real e, real f)
#else
real3 NeutralCurve(real3 x, real a, real b, real c, real d, real e, real f)
#endif
{
return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
}
#define TONEMAPPING_CLAMP_MAX 435.18712 //(-b + sqrt(b * b - 4 * a * (HALF_MAX - d * f))) / (2 * a * whiteScale)
//Extremely high values cause NaN output when using fp16, we clamp to avoid the performace hit of switching to fp32
//The overflow happens in (x * (a * x + b) + d * f) of the NeutralCurve, highest value that avoids fp16 precision errors is ~571.56873
//Since whiteScale is constant (~1.31338) max input is ~435.18712
real3 NeutralTonemap(real3 x)
{
// Tonemap
const real a = 0.2;
const real b = 0.29;
const real c = 0.24;
const real d = 0.272;
const real e = 0.02;
const real f = 0.3;
const real whiteLevel = 5.3;
const real whiteClip = 1.0;
#if defined(SHADER_API_MOBILE)
x = min(x, TONEMAPPING_CLAMP_MAX);
#endif
real3 whiteScale = (1.0).xxx / NeutralCurve(whiteLevel, a, b, c, d, e, f);
x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
x *= whiteScale;
// Post-curve white point adjustment
x /= whiteClip.xxx;
return x;
}
// Raw, unoptimized version of John Hable's artist-friendly tone curve
// Input is linear RGB
real EvalCustomSegment(real x, real4 segmentA, real2 segmentB)
{
const real kOffsetX = segmentA.x;
const real kOffsetY = segmentA.y;
const real kScaleX = segmentA.z;
const real kScaleY = segmentA.w;
const real kLnA = segmentB.x;
const real kB = segmentB.y;
real x0 = (x - kOffsetX) * kScaleX;
real y0 = (x0 > 0.0) ? exp(kLnA + kB * log(x0)) : 0.0;
return y0 * kScaleY + kOffsetY;
}
real EvalCustomCurve(real x, real3 curve, real4 toeSegmentA, real2 toeSegmentB, real4 midSegmentA, real2 midSegmentB, real4 shoSegmentA, real2 shoSegmentB)
{
real4 segmentA;
real2 segmentB;
if (x < curve.y)
{
segmentA = toeSegmentA;
segmentB = toeSegmentB;
}
else if (x < curve.z)
{
segmentA = midSegmentA;
segmentB = midSegmentB;
}
else
{
segmentA = shoSegmentA;
segmentB = shoSegmentB;
}
return EvalCustomSegment(x, segmentA, segmentB);
}
// curve: x: inverseWhitePoint, y: x0, z: x1
real3 CustomTonemap(real3 x, real3 curve, real4 toeSegmentA, real2 toeSegmentB, real4 midSegmentA, real2 midSegmentB, real4 shoSegmentA, real2 shoSegmentB)
{
real3 normX = x * curve.x;
real3 ret;
ret.x = EvalCustomCurve(normX.x, curve, toeSegmentA, toeSegmentB, midSegmentA, midSegmentB, shoSegmentA, shoSegmentB);
ret.y = EvalCustomCurve(normX.y, curve, toeSegmentA, toeSegmentB, midSegmentA, midSegmentB, shoSegmentA, shoSegmentB);
ret.z = EvalCustomCurve(normX.z, curve, toeSegmentA, toeSegmentB, midSegmentA, midSegmentB, shoSegmentA, shoSegmentB);
return ret;
}
// Filmic tonemapping (ACES fitting, unless TONEMAPPING_USE_FULL_ACES is set to 1)
// Input is ACES2065-1 (AP0 w/ linear encoding)
#define TONEMAPPING_USE_FULL_ACES 0
float3 AcesTonemap(float3 aces)
{
#if TONEMAPPING_USE_FULL_ACES
float3 oces = RRT(aces);
float3 odt = ODT_RGBmonitor_100nits_dim(oces);
return odt;
#else
// --- Glow module --- //
float saturation = rgb_2_saturation(aces);
float ycIn = rgb_2_yc(aces);
float s = sigmoid_shaper((saturation - 0.4) / 0.2);
float addedGlow = 1.0 + glow_fwd(ycIn, RRT_GLOW_GAIN * s, RRT_GLOW_MID);
aces *= addedGlow;
// --- Red modifier --- //
float hue = rgb_2_hue(aces);
float centeredHue = center_hue(hue, RRT_RED_HUE);
float hueWeight;
{
//hueWeight = cubic_basis_shaper(centeredHue, RRT_RED_WIDTH);
hueWeight = smoothstep(0.0, 1.0, 1.0 - abs(2.0 * centeredHue / RRT_RED_WIDTH));
hueWeight *= hueWeight;
}
aces.r += hueWeight * saturation * (RRT_RED_PIVOT - aces.r) * (1.0 - RRT_RED_SCALE);
// --- ACES to RGB rendering space --- //
float3 acescg = max(0.0, ACES_to_ACEScg(aces));
// --- Global desaturation --- //
//acescg = mul(RRT_SAT_MAT, acescg);
acescg = lerp(dot(acescg, AP1_RGB2Y).xxx, acescg, RRT_SAT_FACTOR.xxx);
// Luminance fitting of *RRT.a1.0.3 + ODT.Academy.RGBmonitor_100nits_dim.a1.0.3*.
// https://github.com/colour-science/colour-unity/blob/master/Assets/Colour/Notebooks/CIECAM02_Unity.ipynb
// RMSE: 0.0012846272106
#if defined(SHADER_API_SWITCH) // Fix floating point overflow on extremely large values.
const float a = 2.785085 * 0.01;
const float b = 0.107772 * 0.01;
const float c = 2.936045 * 0.01;
const float d = 0.887122 * 0.01;
const float e = 0.806889 * 0.01;
float3 x = acescg;
float3 rgbPost = ((a * x + b)) / ((c * x + d) + e/(x + FLT_MIN));
#else
const float a = 2.785085;
const float b = 0.107772;
const float c = 2.936045;
const float d = 0.887122;
const float e = 0.806889;
float3 x = acescg;
float3 rgbPost = (x * (a * x + b)) / (x * (c * x + d) + e);
#endif
// Scale luminance to linear code value
// float3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK);
// Apply gamma adjustment to compensate for dim surround
float3 linearCV = darkSurround_to_dimSurround(rgbPost);
// Apply desaturation to compensate for luminance difference
//linearCV = mul(ODT_SAT_MAT, color);
linearCV = lerp(dot(linearCV, AP1_RGB2Y).xxx, linearCV, ODT_SAT_FACTOR.xxx);
// Convert to display primary encoding
// Rendering space RGB to XYZ
float3 XYZ = mul(AP1_2_XYZ_MAT, linearCV);
// Apply CAT from ACES white point to assumed observer adapted white point
XYZ = mul(D60_2_D65_CAT, XYZ);
// CIE XYZ to display primaries
linearCV = mul(XYZ_2_REC709_MAT, XYZ);
return linearCV;
#endif
}
// RGBM encode/decode
static const float kRGBMRange = 8.0;
half4 EncodeRGBM(half3 color)
{
color *= 1.0 / kRGBMRange;
half m = max(max(color.x, color.y), max(color.z, 1e-5));
m = ceil(m * 255) / 255;
return half4(color / m, m);
}
half3 DecodeRGBM(half4 rgbm)
{
return rgbm.xyz * rgbm.w * kRGBMRange;
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_COLOR_INCLUDED

View File

@@ -0,0 +1,18 @@
#ifndef UNITY_COMMON_DEPRECATED_INCLUDED
#define UNITY_COMMON_DEPRECATED_INCLUDED
// Function that are in this file shouldn't be use. they are obsolete and could be removed in the future
// they are here to keep compatibility with previous version
#if !defined(SHADER_API_GLES)
// Please use void LODDitheringTransition(uint2 fadeMaskSeed, float ditherFactor)
void LODDitheringTransition(uint3 fadeMaskSeed, float ditherFactor)
{
ditherFactor = ditherFactor < 0.0 ? 1 + ditherFactor : ditherFactor;
float p = GenerateHashedRandomFloat(fadeMaskSeed);
p = (ditherFactor >= 0.5) ? p : 1 - p;
clip(ditherFactor - p);
}
#endif
#endif

View File

@@ -0,0 +1,466 @@
#ifndef UNITY_COMMON_LIGHTING_INCLUDED
#define UNITY_COMMON_LIGHTING_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
// Ligthing convention
// Light direction is oriented backward (-Z). i.e in shader code, light direction is -lightData.forward
//-----------------------------------------------------------------------------
// Helper functions
//-----------------------------------------------------------------------------
// Performs the mapping of the vector 'v' centered within the axis-aligned cube
// of dimensions [-1, 1]^3 to a vector centered within the unit sphere.
// The function expects 'v' to be within the cube (possibly unexpected results otherwise).
// Ref: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
real3 MapCubeToSphere(real3 v)
{
real3 v2 = v * v;
real2 vr3 = v2.xy * rcp(3.0);
return v * sqrt((real3)1.0 - 0.5 * v2.yzx - 0.5 * v2.zxy + vr3.yxx * v2.zzy);
}
// Computes the squared magnitude of the vector computed by MapCubeToSphere().
real ComputeCubeToSphereMapSqMagnitude(real3 v)
{
real3 v2 = v * v;
// Note: dot(v, v) is often computed before this function is called,
// so the compiler should optimize and use the precomputed result here.
return dot(v, v) - v2.x * v2.y - v2.y * v2.z - v2.z * v2.x + v2.x * v2.y * v2.z;
}
// texelArea = 4.0 / (resolution * resolution).
// Ref: http://bpeers.com/blog/?itemid=1017
// This version is less accurate, but much faster than this one:
// http://www.rorydriscoll.com/2012/01/15/cubemap-texel-solid-angle/
real ComputeCubemapTexelSolidAngle(real3 L, real texelArea)
{
// Stretch 'L' by (1/d) so that it points at a side of a [-1, 1]^2 cube.
real d = Max3(abs(L.x), abs(L.y), abs(L.z));
// Since 'L' is a unit vector, we can directly compute its
// new (inverse) length without dividing 'L' by 'd' first.
real invDist = d;
// dw = dA * cosTheta / (dist * dist), cosTheta = 1.0 / dist,
// where 'dA' is the area of the cube map texel.
return texelArea * invDist * invDist * invDist;
}
// Only makes sense for Monte-Carlo integration.
// Normalize by dividing by the total weight (or the number of samples) in the end.
// Integrate[6*(u^2+v^2+1)^(-3/2), {u,-1,1},{v,-1,1}] = 4 * Pi
// Ref: "Stupid Spherical Harmonics Tricks", p. 9.
real ComputeCubemapTexelSolidAngle(real2 uv)
{
real u = uv.x, v = uv.y;
return pow(1 + u * u + v * v, -1.5);
}
real ConvertEvToLuminance(real ev)
{
return exp2(ev - 3.0);
}
real ConvertLuminanceToEv(real luminance)
{
real k = 12.5f;
return log2((luminance * 100.0) / k);
}
//-----------------------------------------------------------------------------
// Attenuation functions
//-----------------------------------------------------------------------------
// Ref: Moving Frostbite to PBR.
// Non physically based hack to limit light influence to attenuationRadius.
// Square the result to smoothen the function.
real DistanceWindowing(real distSquare, real rangeAttenuationScale, real rangeAttenuationBias)
{
// If (range attenuation is enabled)
// rangeAttenuationScale = 1 / r^2
// rangeAttenuationBias = 1
// Else
// rangeAttenuationScale = 2^12 / r^2
// rangeAttenuationBias = 2^24
return saturate(rangeAttenuationBias - Sq(distSquare * rangeAttenuationScale));
}
real SmoothDistanceWindowing(real distSquare, real rangeAttenuationScale, real rangeAttenuationBias)
{
real factor = DistanceWindowing(distSquare, rangeAttenuationScale, rangeAttenuationBias);
return Sq(factor);
}
#define PUNCTUAL_LIGHT_THRESHOLD 0.01 // 1cm (in Unity 1 is 1m)
// Return physically based quadratic attenuation + influence limit to reach 0 at attenuationRadius
real SmoothWindowedDistanceAttenuation(real distSquare, real distRcp, real rangeAttenuationScale, real rangeAttenuationBias)
{
real attenuation = min(distRcp, 1.0 / PUNCTUAL_LIGHT_THRESHOLD);
attenuation *= DistanceWindowing(distSquare, rangeAttenuationScale, rangeAttenuationBias);
// Effectively results in (distRcp)^2 * SmoothDistanceWindowing(...).
return Sq(attenuation);
}
// Square the result to smoothen the function.
real AngleAttenuation(real cosFwd, real lightAngleScale, real lightAngleOffset)
{
return saturate(cosFwd * lightAngleScale + lightAngleOffset);
}
real SmoothAngleAttenuation(real cosFwd, real lightAngleScale, real lightAngleOffset)
{
real attenuation = AngleAttenuation(cosFwd, lightAngleScale, lightAngleOffset);
return Sq(attenuation);
}
// Combines SmoothWindowedDistanceAttenuation() and SmoothAngleAttenuation() in an efficient manner.
// distances = {d, d^2, 1/d, d_proj}, where d_proj = dot(lightToSample, lightData.forward).
real PunctualLightAttenuation(real4 distances, real rangeAttenuationScale, real rangeAttenuationBias,
real lightAngleScale, real lightAngleOffset)
{
real distSq = distances.y;
real distRcp = distances.z;
real distProj = distances.w;
real cosFwd = distProj * distRcp;
real attenuation = min(distRcp, 1.0 / PUNCTUAL_LIGHT_THRESHOLD);
attenuation *= DistanceWindowing(distSq, rangeAttenuationScale, rangeAttenuationBias);
attenuation *= AngleAttenuation(cosFwd, lightAngleScale, lightAngleOffset);
// Effectively results in SmoothWindowedDistanceAttenuation(...) * SmoothAngleAttenuation(...).
return Sq(attenuation);
}
// Applies SmoothDistanceWindowing() after transforming the attenuation ellipsoid into a sphere.
// If r = rsqrt(invSqRadius), then the ellipsoid is defined s.t. r1 = r / invAspectRatio, r2 = r3 = r.
// The transformation is performed along the major axis of the ellipsoid (corresponding to 'r1').
// Both the ellipsoid (e.i. 'axis') and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
real EllipsoidalDistanceAttenuation(real3 unL, real3 axis, real invAspectRatio,
real rangeAttenuationScale, real rangeAttenuationBias)
{
// Project the unnormalized light vector onto the axis.
real projL = dot(unL, axis);
// Transform the light vector so that we can work with
// with the ellipsoid as if it was a sphere with the radius of light's range.
real diff = projL - projL * invAspectRatio;
unL -= diff * axis;
real sqDist = dot(unL, unL);
return SmoothDistanceWindowing(sqDist, rangeAttenuationScale, rangeAttenuationBias);
}
// Applies SmoothDistanceWindowing() using the axis-aligned ellipsoid of the given dimensions.
// Both the ellipsoid and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
real EllipsoidalDistanceAttenuation(real3 unL, real3 invHalfDim,
real rangeAttenuationScale, real rangeAttenuationBias)
{
// Transform the light vector so that we can work with
// with the ellipsoid as if it was a unit sphere.
unL *= invHalfDim;
real sqDist = dot(unL, unL);
return SmoothDistanceWindowing(sqDist, rangeAttenuationScale, rangeAttenuationBias);
}
// Applies SmoothDistanceWindowing() after mapping the axis-aligned box to a sphere.
// If the diagonal of the box is 'd', invHalfDim = rcp(0.5 * d).
// Both the box and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the box.
real BoxDistanceAttenuation(real3 unL, real3 invHalfDim,
real rangeAttenuationScale, real rangeAttenuationBias)
{
real attenuation = 0.0;
// Transform the light vector so that we can work with
// with the box as if it was a [-1, 1]^2 cube.
unL *= invHalfDim;
// Our algorithm expects the input vector to be within the cube.
if (!(Max3(abs(unL.x), abs(unL.y), abs(unL.z)) > 1.0))
{
real sqDist = ComputeCubeToSphereMapSqMagnitude(unL);
attenuation = SmoothDistanceWindowing(sqDist, rangeAttenuationScale, rangeAttenuationBias);
}
return attenuation;
}
//-----------------------------------------------------------------------------
// IES Helper
//-----------------------------------------------------------------------------
real2 GetIESTextureCoordinate(real3x3 lightToWord, real3 L)
{
// IES need to be sample in light space
real3 dir = mul(lightToWord, -L); // Using matrix on left side do a transpose
// convert to spherical coordinate
real2 sphericalCoord; // .x is theta, .y is phi
// Texture is encoded with cos(phi), scale from -1..1 to 0..1
sphericalCoord.y = (dir.z * 0.5) + 0.5;
real theta = atan2(dir.y, dir.x);
sphericalCoord.x = theta * INV_TWO_PI;
return sphericalCoord;
}
//-----------------------------------------------------------------------------
// Lighting functions
//-----------------------------------------------------------------------------
// Ref: Horizon Occlusion for Normal Mapped Reflections: http://marmosetco.tumblr.com/post/81245981087
real GetHorizonOcclusion(real3 V, real3 normalWS, real3 vertexNormal, real horizonFade)
{
real3 R = reflect(-V, normalWS);
real specularOcclusion = saturate(1.0 + horizonFade * dot(R, vertexNormal));
// smooth it
return specularOcclusion * specularOcclusion;
}
// Ref: Moving Frostbite to PBR - Gotanda siggraph 2011
// Return specular occlusion based on ambient occlusion (usually get from SSAO) and view/roughness info
real GetSpecularOcclusionFromAmbientOcclusion(real NdotV, real ambientOcclusion, real roughness)
{
return saturate(PositivePow(NdotV + ambientOcclusion, exp2(-16.0 * roughness - 1.0)) - 1.0 + ambientOcclusion);
}
// ref: Practical Realtime Strategies for Accurate Indirect Occlusion
// Update ambient occlusion to colored ambient occlusion based on statitics of how light is bouncing in an object and with the albedo of the object
real3 GTAOMultiBounce(real visibility, real3 albedo)
{
real3 a = 2.0404 * albedo - 0.3324;
real3 b = -4.7951 * albedo + 0.6417;
real3 c = 2.7552 * albedo + 0.6903;
real x = visibility;
return max(x, ((x * a + b) * x + c) * x);
}
// Based on Oat and Sander's 2008 technique
// Area/solidAngle of intersection of two cone
real SphericalCapIntersectionSolidArea(real cosC1, real cosC2, real cosB)
{
real r1 = FastACos(cosC1);
real r2 = FastACos(cosC2);
real rd = FastACos(cosB);
real area = 0.0;
if (rd <= max(r1, r2) - min(r1, r2))
{
// One cap is completely inside the other
area = TWO_PI - TWO_PI * max(cosC1, cosC2);
}
else if (rd >= r1 + r2)
{
// No intersection exists
area = 0.0;
}
else
{
real diff = abs(r1 - r2);
real den = r1 + r2 - diff;
real x = 1.0 - saturate((rd - diff) / max(den, 0.0001));
area = smoothstep(0.0, 1.0, x);
area *= TWO_PI - TWO_PI * max(cosC1, cosC2);
}
return area;
}
// ref: Practical Realtime Strategies for Accurate Indirect Occlusion
// http://blog.selfshadow.com/publications/s2016-shading-course/#course_content
// Original Cone-Cone method with cosine weighted assumption (p129 s2016_pbs_activision_occlusion)
real GetSpecularOcclusionFromBentAO(real3 V, real3 bentNormalWS, real3 normalWS, real ambientOcclusion, real roughness)
{
// Retrieve cone angle
// Ambient occlusion is cosine weighted, thus use following equation. See slide 129
real cosAv = sqrt(1.0 - ambientOcclusion);
roughness = max(roughness, 0.01); // Clamp to 0.01 to avoid edge cases
real cosAs = exp2((-log(10.0) / log(2.0)) * Sq(roughness));
real cosB = dot(bentNormalWS, reflect(-V, normalWS));
return SphericalCapIntersectionSolidArea(cosAv, cosAs, cosB) / (TWO_PI * (1.0 - cosAs));
}
// Ref: Steve McAuley - Energy-Conserving Wrapped Diffuse
real ComputeWrappedDiffuseLighting(real NdotL, real w)
{
return saturate((NdotL + w) / ((1.0 + w) * (1.0 + w)));
}
// Jimenez variant for eye
real ComputeWrappedPowerDiffuseLighting(real NdotL, real w, real p)
{
return pow(saturate((NdotL + w) / (1.0 + w)), p) * (p + 1) / (w * 2.0 + 2.0);
}
// Ref: The Technical Art of Uncharted 4 - Brinck and Maximov 2016
real ComputeMicroShadowing(real AO, real NdotL, real opacity)
{
real aperture = 2.0 * AO * AO;
real microshadow = saturate(NdotL + aperture - 1.0);
return lerp(1.0, microshadow, opacity);
}
real3 ComputeShadowColor(real shadow, real3 shadowTint, real penumbraFlag)
{
// The origin expression is
// lerp(real3(1.0, 1.0, 1.0) - ((1.0 - shadow) * (real3(1.0, 1.0, 1.0) - shadowTint))
// , shadow * lerp(shadowTint, lerp(shadowTint, real3(1.0, 1.0, 1.0), shadow), shadow)
// , penumbraFlag);
// it has been simplified to this
real3 invTint = real3(1.0, 1.0, 1.0) - shadowTint;
real shadow3 = shadow * shadow * shadow;
return lerp(real3(1.0, 1.0, 1.0) - ((1.0 - shadow) * invTint)
, shadow3 * invTint + shadow * shadowTint,
penumbraFlag);
}
// This is the same method as the one above. Simply the shadow is a real3 to support colored shadows.
real3 ComputeShadowColor(real3 shadow, real3 shadowTint, real penumbraFlag)
{
// The origin expression is
// lerp(real3(1.0, 1.0, 1.0) - ((1.0 - shadow) * (real3(1.0, 1.0, 1.0) - shadowTint))
// , shadow * lerp(shadowTint, lerp(shadowTint, real3(1.0, 1.0, 1.0), shadow), shadow)
// , penumbraFlag);
// it has been simplified to this
real3 invTint = real3(1.0, 1.0, 1.0) - shadowTint;
real3 shadow3 = shadow * shadow * shadow;
return lerp(real3(1.0, 1.0, 1.0) - ((1.0 - shadow) * invTint)
, shadow3 * invTint + shadow * shadowTint,
penumbraFlag);
}
//-----------------------------------------------------------------------------
// Helper functions
//--------------------------------------------------------------------------- --
// Ref: "Crafting a Next-Gen Material Pipeline for The Order: 1886".
real ClampNdotV(real NdotV)
{
return max(NdotV, 0.0001); // Approximately 0.0057 degree bias
}
// Helper function to return a set of common angle used when evaluating BSDF
// NdotL and NdotV are unclamped
void GetBSDFAngle(real3 V, real3 L, real NdotL, real NdotV,
out real LdotV, out real NdotH, out real LdotH, out real invLenLV)
{
// Optimized math. Ref: PBR Diffuse Lighting for GGX + Smith Microsurfaces (slide 114).
LdotV = dot(L, V);
invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)), clamp to avoid rsqrt(0) = inf, inf * 0 = NaN
NdotH = saturate((NdotL + NdotV) * invLenLV);
LdotH = saturate(invLenLV * LdotV + invLenLV);
}
// Inputs: normalized normal and view vectors.
// Outputs: front-facing normal, and the new non-negative value of the cosine of the view angle.
// Important: call Orthonormalize() on the tangent and recompute the bitangent afterwards.
real3 GetViewReflectedNormal(real3 N, real3 V, out real NdotV)
{
// Fragments of front-facing geometry can have back-facing normals due to interpolation,
// normal mapping and decals. This can cause visible artifacts from both direct (negative or
// extremely high values) and indirect (incorrect lookup direction) lighting.
// There are several ways to avoid this problem. To list a few:
//
// 1. Setting { NdotV = max(<N,V>, SMALL_VALUE) }. This effectively removes normal mapping
// from the affected fragments, making the surface appear flat.
//
// 2. Setting { NdotV = abs(<N,V>) }. This effectively reverses the convexity of the surface.
// It also reduces light leaking from non-shadow-casting lights. Note that 'NdotV' can still
// be 0 in this case.
//
// It's important to understand that simply changing the value of the cosine is insufficient.
// For one, it does not solve the incorrect lookup direction problem, since the normal itself
// is not modified. There is a more insidious issue, however. 'NdotV' is a constituent element
// of the mathematical system describing the relationships between different vectors - and
// not just normal and view vectors, but also light vectors, half vectors, tangent vectors, etc.
// Changing only one angle (or its cosine) leaves the system in an inconsistent state, where
// certain relationships can take on different values depending on whether 'NdotV' is used
// in the calculation or not. Therefore, it is important to change the normal (or another
// vector) in order to leave the system in a consistent state.
//
// We choose to follow the conceptual approach (2) by reflecting the normal around the
// (<N,V> = 0) boundary if necessary, as it allows us to preserve some normal mapping details.
NdotV = dot(N, V);
// N = (NdotV >= 0.0) ? N : (N - 2.0 * NdotV * V);
N += (2.0 * saturate(-NdotV)) * V;
NdotV = abs(NdotV);
return N;
}
// Generates an orthonormal (row-major) basis from a unit vector. TODO: make it column-major.
// The resulting rotation matrix has the determinant of +1.
// Ref: 'ortho_basis_pixar_r2' from http://marc-b-reynolds.github.io/quaternions/2016/07/06/Orthonormal.html
real3x3 GetLocalFrame(real3 localZ)
{
real x = localZ.x;
real y = localZ.y;
real z = localZ.z;
real sz = FastSign(z);
real a = 1 / (sz + z);
real ya = y * a;
real b = x * ya;
real c = x * sz;
real3 localX = real3(c * x * a - 1, sz * b, c);
real3 localY = real3(b, y * ya - sz, y);
// Note: due to the quaternion formulation, the generated frame is rotated by 180 degrees,
// s.t. if localZ = {0, 0, 1}, then localX = {-1, 0, 0} and localY = {0, -1, 0}.
return real3x3(localX, localY, localZ);
}
// Generates an orthonormal (row-major) basis from a unit vector. TODO: make it column-major.
// The resulting rotation matrix has the determinant of +1.
real3x3 GetLocalFrame(real3 localZ, real3 localX)
{
real3 localY = cross(localZ, localX);
return real3x3(localX, localY, localZ);
}
// Construct a right-handed view-dependent orthogonal basis around the normal:
// b0-b2 is the view-normal aka reflection plane.
real3x3 GetOrthoBasisViewNormal(real3 V, real3 N, real unclampedNdotV, bool testSingularity = false)
{
real3x3 orthoBasisViewNormal;
if (testSingularity && (abs(1.0 - unclampedNdotV) <= FLT_EPS))
{
// In this case N == V, and azimuth orientation around N shouldn't matter for the caller,
// we can use any quaternion-based method, like Frisvad or Reynold's (Pixar):
orthoBasisViewNormal = GetLocalFrame(N);
}
else
{
orthoBasisViewNormal[0] = normalize(V - N * unclampedNdotV);
orthoBasisViewNormal[2] = N;
orthoBasisViewNormal[1] = cross(orthoBasisViewNormal[2], orthoBasisViewNormal[0]);
}
return orthoBasisViewNormal;
}
// Move this here since it's used by both LightLoop.hlsl and RaytracingLightLoop.hlsl
bool IsMatchingLightLayer(uint lightLayers, uint renderingLayers)
{
return (lightLayers & renderingLayers) != 0;
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_COMMON_LIGHTING_INCLUDED

View File

@@ -0,0 +1,341 @@
#ifndef UNITY_COMMON_MATERIAL_INCLUDED
#define UNITY_COMMON_MATERIAL_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
//-----------------------------------------------------------------------------
// Define constants
//-----------------------------------------------------------------------------
#define DEFAULT_SPECULAR_VALUE 0.04
// Following constant are used when we use clear coat properties that can't be store in the Gbuffer (with the Lit shader)
#define CLEAR_COAT_IOR 1.5
#define CLEAR_COAT_IETA (1.0 / CLEAR_COAT_IOR) // IETA is the inverse eta which is the ratio of IOR of two interface
#define CLEAR_COAT_F0 0.04 // IORToFresnel0(CLEAR_COAT_IOR)
#define CLEAR_COAT_ROUGHNESS 0.01
#define CLEAR_COAT_PERCEPTUAL_SMOOTHNESS RoughnessToPerceptualSmoothness(CLEAR_COAT_ROUGHNESS)
#define CLEAR_COAT_PERCEPTUAL_ROUGHNESS RoughnessToPerceptualRoughness(CLEAR_COAT_ROUGHNESS)
//-----------------------------------------------------------------------------
// Helper functions for roughness
//-----------------------------------------------------------------------------
real PerceptualRoughnessToRoughness(real perceptualRoughness)
{
return perceptualRoughness * perceptualRoughness;
}
real RoughnessToPerceptualRoughness(real roughness)
{
return sqrt(roughness);
}
real RoughnessToPerceptualSmoothness(real roughness)
{
return 1.0 - sqrt(roughness);
}
real PerceptualSmoothnessToRoughness(real perceptualSmoothness)
{
return (1.0 - perceptualSmoothness) * (1.0 - perceptualSmoothness);
}
real PerceptualSmoothnessToPerceptualRoughness(real perceptualSmoothness)
{
return (1.0 - perceptualSmoothness);
}
// Beckmann to GGX roughness "conversions":
//
// As also noted for NormalVariance in this file, Beckmann microfacet models use a Gaussian distribution of slopes
// and the roughness parameter absorbs constants in the canonical Gaussian formula and is thus not exactly the variance.
// The relationship is:
//
// roughnessBeckmann^2 = 2 variance (where variance is usually denoted sigma^2 but some comp gfx papers use sigma for
// variance or even sigma for roughness itself.)
//
// Microfacet BRDF models with a GGX NDF implies a Cauchy distribution of slopes (also corresponds to the distribution
// of slopes on an ellipsoid). Cauchy distributions don't have second moments, which precludes having a variance,
// but chopping the far tails of GGX and keeping 94% of the mass yields a distribution with a defined variance where
// we can then relate the roughness of GGX to a variance (see Ray Tracing Gems p153 - the reference is wrong though,
// the Conty paper doesn't mention this at all, but it can be found in stats using quantiles):
//
// roughnessGGX^2 = variance / 2
//
// From the two previous, if we want roughly comparable variances of slopes between a Beckmann and a GGX NDF, we can
// equate the variances and get a conversion of their roughnesses:
//
// 2 * roughnessGGX^2 = roughnessBeckmann^2 / 2 <==>
// 4 * roughnessGGX^2 = roughnessBeckmann^2 <==>
// 2 * roughnessGGX = roughnessBeckmann
//
// (Note that the Ray Tracing Gems paper makes an error on p154 writing sqrt(2) * roughnessGGX = roughnessBeckmann;
// Their validation study using ray tracing and LEADR - which looks good - is for the *variance to GGX* roughness mapping,
// not the Beckmann to GGX roughness "conversion")
real BeckmannRoughnessToGGXRoughness(real roughnessBeckmann)
{
return 0.5 * roughnessBeckmann;
}
real PerceptualRoughnessBeckmannToGGX(real perceptualRoughnessBeckmann)
{
//sqrt(a_ggx) = sqrt(0.5) sqrt(a_beckmann)
return sqrt(0.5) * perceptualRoughnessBeckmann;
}
real GGXRoughnessToBeckmannRoughness(real roughnessGGX)
{
return 2.0 * roughnessGGX;
}
real PerceptualRoughnessToPerceptualSmoothness(real perceptualRoughness)
{
return (1.0 - perceptualRoughness);
}
// WARNING: this has been deprecated, and should not be used!
// Using roughness values of 0 leads to INFs and NANs. The only sensible place to use the roughness
// value of 0 is IBL, so we do not modify the perceptual roughness which is used to select the MIP map level.
// Note: making the constant too small results in aliasing.
real ClampRoughnessForAnalyticalLights(real roughness)
{
return max(roughness, 1.0 / 1024.0);
}
// Given that the GGX model is invalid for a roughness of 0.0. This values have been experimentally evaluated to be the limit for the roughness
// for integration.
real ClampRoughnessForRaytracing(real roughness)
{
return max(roughness, 0.001225);
}
real ClampPerceptualRoughnessForRaytracing(real perceptualRoughness)
{
return max(perceptualRoughness, 0.035);
}
void ConvertValueAnisotropyToValueTB(real value, real anisotropy, out real valueT, out real valueB)
{
// Use the parametrization of Sony Imageworks.
// Ref: Revisiting Physically Based Shading at Imageworks, p. 15.
valueT = value * (1 + anisotropy);
valueB = value * (1 - anisotropy);
}
void ConvertAnisotropyToRoughness(real perceptualRoughness, real anisotropy, out real roughnessT, out real roughnessB)
{
real roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
ConvertValueAnisotropyToValueTB(roughness, anisotropy, roughnessT, roughnessB);
}
void ConvertRoughnessTAndAnisotropyToRoughness(real roughnessT, real anisotropy, out real roughness)
{
roughness = roughnessT / (1 + anisotropy);
}
void ConvertRoughnessToAnisotropy(real roughnessT, real roughnessB, out real anisotropy)
{
anisotropy = ((roughnessT - roughnessB) / max(roughnessT + roughnessB, 0.0001));
}
// WARNING: this has been deprecated, and should not be used!
// Same as ConvertAnisotropyToRoughness but
// roughnessT and roughnessB are clamped, and are meant to be used with punctual and directional lights.
void ConvertAnisotropyToClampRoughness(real perceptualRoughness, real anisotropy, out real roughnessT, out real roughnessB)
{
ConvertAnisotropyToRoughness(perceptualRoughness, anisotropy, roughnessT, roughnessB);
roughnessT = ClampRoughnessForAnalyticalLights(roughnessT);
roughnessB = ClampRoughnessForAnalyticalLights(roughnessB);
}
// Use with stack BRDF (clear coat / coat) - This only used same equation to convert from Blinn-Phong spec power to Beckmann roughness
real RoughnessToVariance(real roughness)
{
return 2.0 / Sq(roughness) - 2.0;
}
real VarianceToRoughness(real variance)
{
return sqrt(2.0 / (variance + 2.0));
}
// Normal Map Filtering - This must match HDRP\Editor\AssetProcessors\NormalMapFilteringTexturePostprocessor.cs - highestVarianceAllowed (TODO: Move in core)
#define NORMALMAP_HIGHEST_VARIANCE 0.03125
float DecodeVariance(float gradientW)
{
return gradientW * NORMALMAP_HIGHEST_VARIANCE;
}
// Return modified perceptualSmoothness based on provided variance (get from GeometricNormalVariance + TextureNormalVariance)
float NormalFiltering(float perceptualSmoothness, float variance, float threshold)
{
float roughness = PerceptualSmoothnessToRoughness(perceptualSmoothness);
// Ref: Geometry into Shading - http://graphics.pixar.com/library/BumpRoughness/paper.pdf - equation (3)
float squaredRoughness = saturate(roughness * roughness + min(2.0 * variance, threshold * threshold)); // threshold can be really low, square the value for easier control
return RoughnessToPerceptualSmoothness(sqrt(squaredRoughness));
}
// Reference: Error Reduction and Simplification for Shading Anti-Aliasing
// Specular antialiasing for geometry-induced normal (and NDF) variations: Tokuyoshi / Kaplanyan et al.'s method.
// This is the deferred approximation, which works reasonably well so we keep it for forward too for now.
// screenSpaceVariance should be at most 0.5^2 = 0.25, as that corresponds to considering
// a gaussian pixel reconstruction kernel with a standard deviation of 0.5 of a pixel, thus 2 sigma covering the whole pixel.
float GeometricNormalVariance(float3 geometricNormalWS, float screenSpaceVariance)
{
float3 deltaU = ddx(geometricNormalWS);
float3 deltaV = ddy(geometricNormalWS);
return screenSpaceVariance * (dot(deltaU, deltaU) + dot(deltaV, deltaV));
}
// Return modified perceptualSmoothness
float GeometricNormalFiltering(float perceptualSmoothness, float3 geometricNormalWS, float screenSpaceVariance, float threshold)
{
float variance = GeometricNormalVariance(geometricNormalWS, screenSpaceVariance);
return NormalFiltering(perceptualSmoothness, variance, threshold);
}
// Normal map filtering based on The Order : 1886 SIGGRAPH course notes implementation.
// Basically Toksvig with an intermediate single vMF lobe induced dispersion (Han et al. 2007)
//
// This returns 2 times the variance of the induced "mesoNDF" lobe (an NDF induced from a section of
// the normal map) from the level 0 mip normals covered by the "current texel".
//
// avgNormalLength gives the dispersion information for the covered normals.
//
// Note that hw filtering on the normal map should be trilinear to be conservative, while anisotropic
// risk underfiltering. Could also compute average normal on the fly with a proper normal map format,
// like Toksvig.
float TextureNormalVariance(float avgNormalLength)
{
float variance = 0.0;
if (avgNormalLength < 1.0)
{
float avgNormLen2 = avgNormalLength * avgNormalLength;
float kappa = (3.0 * avgNormalLength - avgNormalLength * avgNormLen2) / (1.0 - avgNormLen2);
// Ref: Frequency Domain Normal Map Filtering - http://www.cs.columbia.edu/cg/normalmap/normalmap.pdf (equation 21)
// Relationship between between the standard deviation of a Gaussian distribution and the roughness parameter of a Beckmann distribution.
// is roughness^2 = 2 variance (note: variance is sigma^2)
// (Ref: Filtering Distributions of Normals for Shading Antialiasing - Equation just after (14))
// Relationship between gaussian lobe and vMF lobe is 2 * variance = 1 / (2 * kappa) = roughness^2
// (Equation 36 of Normal map filtering based on The Order : 1886 SIGGRAPH course notes implementation).
// So to get variance we must use variance = 1 / (4 * kappa)
variance = 0.25 / kappa;
}
return variance;
}
float TextureNormalFiltering(float perceptualSmoothness, float avgNormalLength, float threshold)
{
float variance = TextureNormalVariance(avgNormalLength);
return NormalFiltering(perceptualSmoothness, variance, threshold);
}
// ----------------------------------------------------------------------------
// Helper for Disney parametrization
// ----------------------------------------------------------------------------
float3 ComputeDiffuseColor(float3 baseColor, float metallic)
{
return baseColor * (1.0 - metallic);
}
float3 ComputeFresnel0(float3 baseColor, float metallic, float dielectricF0)
{
return lerp(dielectricF0.xxx, baseColor, metallic);
}
// ----------------------------------------------------------------------------
// Helper for normal blending
// ----------------------------------------------------------------------------
// ref https://www.gamedev.net/topic/678043-how-to-blend-world-space-normals/#entry5287707
// assume compositing in world space
// Note: Using vtxNormal = real3(0, 0, 1) give the BlendNormalRNM formulation.
// TODO: Untested
real3 BlendNormalWorldspaceRNM(real3 n1, real3 n2, real3 vtxNormal)
{
// Build the shortest-arc quaternion
real4 q = real4(cross(vtxNormal, n2), dot(vtxNormal, n2) + 1.0) / sqrt(2.0 * (dot(vtxNormal, n2) + 1));
// Rotate the normal
return n1 * (q.w * q.w - dot(q.xyz, q.xyz)) + 2 * q.xyz * dot(q.xyz, n1) + 2 * q.w * cross(q.xyz, n1);
}
// ref http://blog.selfshadow.com/publications/blending-in-detail/
// ref https://gist.github.com/selfshadow/8048308
// Reoriented Normal Mapping
// Blending when n1 and n2 are already 'unpacked' and normalised
// assume compositing in tangent space
real3 BlendNormalRNM(real3 n1, real3 n2)
{
real3 t = n1.xyz + real3(0.0, 0.0, 1.0);
real3 u = n2.xyz * real3(-1.0, -1.0, 1.0);
real3 r = (t / t.z) * dot(t, u) - u;
return r;
}
// assume compositing in tangent space
real3 BlendNormal(real3 n1, real3 n2)
{
return normalize(real3(n1.xy * n2.z + n2.xy * n1.z, n1.z * n2.z));
}
// ----------------------------------------------------------------------------
// Helper for triplanar
// ----------------------------------------------------------------------------
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html / http://www.slideshare.net/icastano/cascades-demo-secrets
real3 ComputeTriplanarWeights(real3 normal)
{
// Determine the blend weights for the 3 planar projections.
real3 blendWeights = abs(normal);
// Tighten up the blending zone
blendWeights = (blendWeights - 0.2);
blendWeights = blendWeights * blendWeights * blendWeights; // pow(blendWeights, 3);
// Force weights to sum to 1.0 (very important!)
blendWeights = max(blendWeights, real3(0.0, 0.0, 0.0));
blendWeights /= dot(blendWeights, 1.0);
return blendWeights;
}
// Planar/Triplanar convention for Unity in world space
void GetTriplanarCoordinate(float3 position, out float2 uvXZ, out float2 uvXY, out float2 uvZY)
{
// Caution: This must follow the same rule as what is use for SurfaceGradient triplanar
// TODO: Currently the normal mapping looks wrong without SURFACE_GRADIENT option because we don't handle corretly the tangent space
uvXZ = float2(position.x, position.z);
uvXY = float2(position.x, position.y);
uvZY = float2(position.z, position.y);
}
// ----------------------------------------------------------------------------
// Helper for detail map operation
// ----------------------------------------------------------------------------
real LerpWhiteTo(real b, real t)
{
real oneMinusT = 1.0 - t;
return oneMinusT + b * t;
}
real3 LerpWhiteTo(real3 b, real t)
{
real oneMinusT = 1.0 - t;
return real3(oneMinusT, oneMinusT, oneMinusT) + b * t;
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_COMMON_MATERIAL_INCLUDED

View File

@@ -0,0 +1,14 @@
#ifndef UNITY_COMMON_SHADOW_INCLUDED
#define UNITY_COMMON_SHADOW_INCLUDED
// Ref: https://mynameismjp.wordpress.com/2015/02/18/shadow-sample-update/
// Calculates the offset to use for sampling the shadow map, based on the surface normal
real3 GetShadowPosOffset(real NdotL, real3 normalWS, real2 invShadowMapSize)
{
real texelSize = 2.0 * invShadowMapSize.x;
real offsetScaleNormalize = saturate(1.0 - NdotL);
// return texelSize * OffsetScale * offsetScaleNormalize * normalWS;
return texelSize * offsetScaleNormalize * normalWS;
}
#endif // UNITY_COMMON_SHADOW_INCLUDED

View File

@@ -0,0 +1,279 @@
#ifndef UNITY_DEBUG_INCLUDED
#define UNITY_DEBUG_INCLUDED
#define TRANSPARENCY_OVERDRAW_COST 1.0
#define TRANSPARENCY_OVERDRAW_A 1.0
// Given an enum (represented by an int here), return a color.
// Use for DebugView of enum
real3 GetIndexColor(int index)
{
real3 outColor = real3(1.0, 0.0, 0.0);
if (index == 0)
outColor = real3(1.0, 0.5, 0.5);
else if (index == 1)
outColor = real3(0.5, 1.0, 0.5);
else if (index == 2)
outColor = real3(0.5, 0.5, 1.0);
else if (index == 3)
outColor = real3(1.0, 1.0, 0.5);
else if (index == 4)
outColor = real3(1.0, 0.5, 1.0);
else if (index == 5)
outColor = real3(0.5, 1.0, 1.0);
else if (index == 6)
outColor = real3(0.25, 0.75, 1.0);
else if (index == 7)
outColor = real3(1.0, 0.75, 0.25);
else if (index == 8)
outColor = real3(0.75, 1.0, 0.25);
else if (index == 9)
outColor = real3(0.75, 0.25, 1.0);
else if (index == 10)
outColor = real3(0.25, 1.0, 0.75);
else if (index == 11)
outColor = real3(0.75, 0.75, 0.25);
else if (index == 12)
outColor = real3(0.75, 0.25, 0.75);
else if (index == 13)
outColor = real3(0.25, 0.75, 0.75);
else if (index == 14)
outColor = real3(0.25, 0.25, 0.75);
else if (index == 15)
outColor = real3(0.75, 0.25, 0.25);
return outColor;
}
bool SampleDebugFont(int2 pixCoord, uint digit)
{
if (pixCoord.x < 0 || pixCoord.y < 0 || pixCoord.x >= 5 || pixCoord.y >= 9 || digit > 9)
return false;
#define PACK_BITS25(_x0,_x1,_x2,_x3,_x4,_x5,_x6,_x7,_x8,_x9,_x10,_x11,_x12,_x13,_x14,_x15,_x16,_x17,_x18,_x19,_x20,_x21,_x22,_x23,_x24) (_x0|(_x1<<1)|(_x2<<2)|(_x3<<3)|(_x4<<4)|(_x5<<5)|(_x6<<6)|(_x7<<7)|(_x8<<8)|(_x9<<9)|(_x10<<10)|(_x11<<11)|(_x12<<12)|(_x13<<13)|(_x14<<14)|(_x15<<15)|(_x16<<16)|(_x17<<17)|(_x18<<18)|(_x19<<19)|(_x20<<20)|(_x21<<21)|(_x22<<22)|(_x23<<23)|(_x24<<24))
#define _ 0
#define x 1
uint fontData[9][2] = {
{ PACK_BITS25(_,_,x,_,_, _,_,x,_,_, _,x,x,x,_, x,x,x,x,x, _,_,_,x,_), PACK_BITS25(x,x,x,x,x, _,x,x,x,_, x,x,x,x,x, _,x,x,x,_, _,x,x,x,_) },
{ PACK_BITS25(_,x,_,x,_, _,x,x,_,_, x,_,_,_,x, _,_,_,_,x, _,_,_,x,_), PACK_BITS25(x,_,_,_,_, x,_,_,_,x, _,_,_,_,x, x,_,_,_,x, x,_,_,_,x) },
{ PACK_BITS25(x,_,_,_,x, x,_,x,_,_, x,_,_,_,x, _,_,_,x,_, _,_,x,x,_), PACK_BITS25(x,_,_,_,_, x,_,_,_,_, _,_,_,x,_, x,_,_,_,x, x,_,_,_,x) },
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,_,_,_,x, _,_,x,_,_, _,x,_,x,_), PACK_BITS25(x,_,x,x,_, x,_,_,_,_, _,_,_,x,_, x,_,_,_,x, x,_,_,_,x) },
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,_,_,x,_, _,x,x,x,_, _,x,_,x,_), PACK_BITS25(x,x,_,_,x, x,x,x,x,_, _,_,x,_,_, _,x,x,x,_, _,x,x,x,x) },
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,_,x,_,_, _,_,_,_,x, x,_,_,x,_), PACK_BITS25(_,_,_,_,x, x,_,_,_,x, _,_,x,_,_, x,_,_,_,x, _,_,_,_,x) },
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,x,_,_,_, _,_,_,_,x, x,x,x,x,x), PACK_BITS25(_,_,_,_,x, x,_,_,_,x, _,x,_,_,_, x,_,_,_,x, _,_,_,_,x) },
{ PACK_BITS25(_,x,_,x,_, _,_,x,_,_, x,_,_,_,_, x,_,_,_,x, _,_,_,x,_), PACK_BITS25(x,_,_,_,x, x,_,_,_,x, _,x,_,_,_, x,_,_,_,x, x,_,_,_,x) },
{ PACK_BITS25(_,_,x,_,_, x,x,x,x,x, x,x,x,x,x, _,x,x,x,_, _,_,_,x,_), PACK_BITS25(_,x,x,x,_, _,x,x,x,_, _,x,_,_,_, _,x,x,x,_, _,x,x,x,_) }
};
#undef _
#undef x
#undef PACK_BITS25
return (fontData[8 - pixCoord.y][digit >= 5] >> ((digit % 5) * 5 + pixCoord.x)) & 1;
}
bool SampleDebugFontNumber(int2 pixCoord, uint number)
{
pixCoord.y -= 4;
if (number <= 9)
{
return SampleDebugFont(pixCoord - int2(6, 0), number);
}
else
{
return (SampleDebugFont(pixCoord, number / 10) | SampleDebugFont(pixCoord - int2(6, 0), number % 10));
}
}
float4 GetStreamingMipColor(uint mipCount, float4 mipInfo)
{
// alpha is amount to blend with source color (0.0 = use original, 1.0 = use new color)
// mipInfo :
// x = quality setings minStreamingMipLevel
// y = original mip count for texture
// z = desired on screen mip level
// w = 0
uint originalTextureMipCount = uint(mipInfo.y);
// If material/shader mip info (original mip level) has not been set its not a streamed texture
if (originalTextureMipCount == 0)
return float4(1.0, 1.0, 1.0, 0.0);
uint desiredMipLevel = uint(mipInfo.z);
uint mipCountDesired = uint(originalTextureMipCount)-uint(desiredMipLevel);
if (mipCount == 0)
{
// Magenta if mip count invalid
return float4(1.0, 0.0, 1.0, 1.0);
}
else if (mipCount < mipCountDesired)
{
// red tones when not at the desired mip level (reduction due to budget). Brighter is further from original, alpha 0 when at desired
float ratioToDesired = float(mipCount) / float(mipCountDesired);
return float4(1.0, 0.0, 0.0, 1.0 - ratioToDesired);
}
else if (mipCount >= originalTextureMipCount)
{
// original color when at (or beyond) original mip count
return float4(1.0, 1.0, 1.0, 0.0);
}
else
{
// green tones when not at the original mip level. Brighter is closer to original, alpha 0 when at original
float ratioToOriginal = float(mipCount) / float(originalTextureMipCount);
return float4(0.0, 1.0, 0.0, 1.0 - ratioToOriginal);
}
}
float4 GetSimpleMipCountColor(uint mipCount)
{
// Grey scale for mip counts where mip count of 14 = white
float mipCountColor = float(mipCount) / 14.0;
float4 color = float4(mipCountColor, mipCountColor, mipCountColor, 1.0f);
// alpha is amount to blend with source color (0.0 = use original, 1.0 = use new color)
// Magenta is no valid mip count
// Red if greater than 14
return mipCount==0 ? float4(1.0, 0.0, 1.0, 1.0) : (mipCount > 14 ? float4(1.0, 0.0, 0.0, 1.0) : color );
}
float4 GetMipLevelColor(float2 uv, float4 texelSize)
{
// Push down into colors list to "optimal level" in following table.
// .zw is texture width,height so *2 is down one mip, *4 is down two mips
texelSize.zw *= 4.0;
float mipLevel = ComputeTextureLOD(uv, texelSize.wz);
mipLevel = clamp(mipLevel, 0.0, 5.0 - 0.0001);
float4 colors[6] = {
float4(0.0, 0.0, 1.0, 0.8), // 0 BLUE = too little texture detail
float4(0.0, 0.5, 1.0, 0.4), // 1
float4(1.0, 1.0, 1.0, 0.0), // 2 = optimal level
float4(1.0, 0.7, 0.0, 0.2), // 3 (YELLOW tint)
float4(1.0, 0.3, 0.0, 0.6), // 4 (clamped mipLevel 4.9999)
float4(1.0, 0.0, 0.0, 0.8) // 5 RED = too much texture detail (max blended value)
};
int mipLevelInt = floor(mipLevel);
float t = frac(mipLevel);
float4 a = colors[mipLevelInt];
float4 b = colors[mipLevelInt + 1];
float4 color = lerp(a, b, t);
return color;
}
float3 GetDebugMipColor(float3 originalColor, Texture2D tex, float4 texelSize, float2 uv)
{
// https://aras-p.info/blog/2011/05/03/a-way-to-visualize-mip-levels/
float4 mipColor= GetMipLevelColor(uv, texelSize);
return lerp(originalColor, mipColor.rgb, mipColor.a);
}
float3 GetDebugMipCountColor(float3 originalColor, Texture2D tex)
{
uint mipCount = GetMipCount(tex);
float4 mipColor = GetSimpleMipCountColor(mipCount);
return lerp(originalColor, mipColor.rgb, mipColor.a);
}
float3 GetDebugStreamingMipColor(Texture2D tex, float4 mipInfo)
{
uint mipCount = GetMipCount(tex);
return GetStreamingMipColor(mipCount, mipInfo).xyz;
}
float3 GetDebugStreamingMipColorBlended(float3 originalColor, Texture2D tex, float4 mipInfo)
{
uint mipCount = GetMipCount(tex);
float4 mipColor = GetStreamingMipColor(mipCount, mipInfo);
return lerp(originalColor, mipColor.rgb, mipColor.a);
}
float3 GetDebugMipColorIncludingMipReduction(float3 originalColor, Texture2D tex, float4 texelSize, float2 uv, float4 mipInfo)
{
uint originalTextureMipCount = uint(mipInfo.y);
if (originalTextureMipCount != 0)
{
// mipInfo :
// x = quality setings minStreamingMipLevel
// y = original mip count for texture
// z = desired on screen mip level
// w = 0
// Mip count has been reduced but the texelSize was not updated to take that into account
uint mipCount = GetMipCount(tex);
uint mipReductionLevel = originalTextureMipCount - mipCount;
uint mipReductionFactor = 1 << mipReductionLevel;
if (mipReductionFactor)
{
float oneOverMipReductionFactor = 1.0 / mipReductionFactor;
// texelSize.xy *= mipReductionRatio; // Unused in GetDebugMipColor so lets not re-calculate it
texelSize.zw *= oneOverMipReductionFactor;
}
}
return GetDebugMipColor(originalColor, tex, texelSize, uv);
}
// mipInfo :
// x = quality setings minStreamingMipLevel
// y = original mip count for texture
// z = desired on screen mip level
// w = 0
float3 GetDebugMipReductionColor(Texture2D tex, float4 mipInfo)
{
float3 outColor = float3(1.0, 0.0, 1.0); // Can't calculate without original mip count - return magenta
uint originalTextureMipCount = uint(mipInfo.y);
if (originalTextureMipCount != 0)
{
// Mip count has been reduced but the texelSize was not updated to take that into account
uint mipCount = GetMipCount(tex);
uint mipReductionLevel = originalTextureMipCount - mipCount;
float mipCol = float(mipReductionLevel) / 14.0;
outColor = float3(0, mipCol, 0);
}
return outColor;
}
// Convert an arbitrary range to color base on threshold provide to the function, threshold must be in growing order
real3 GetColorCodeFunction(real value, real4 threshold)
{
const real3 red = { 1.0, 0.0, 0.0 };
const real3 lightGreen = { 0.5, 1.0, 0.5 };
const real3 darkGreen = { 0.1, 1.0, 0.1 };
const real3 yellow = { 1.0, 1.0, 0.0 };
real3 outColor = red;
if (value < threshold[0])
{
outColor = red;
}
else if (value >= threshold[0] && value < threshold[1])
{
real scale = (value - threshold[0]) / (threshold[1] - threshold[0]);
outColor = lerp(red, darkGreen, scale);
}
else if (value >= threshold[1] && value < threshold[2])
{
real scale = (value - threshold[1]) / (threshold[2] - threshold[1]);
outColor = lerp(darkGreen, lightGreen, scale);
}
else if (value >= threshold[2] && value < threshold[3])
{
real scale = (value - threshold[2]) / (threshold[2] - threshold[2]);
outColor = lerp(lightGreen, yellow, scale);
}
else
{
outColor = yellow;
}
return outColor;
}
#endif // UNITY_DEBUG_INCLUDED

View File

@@ -0,0 +1,4 @@
// This file is only to force Unity to load the ShaderLibrary's hlsl files in visual studio project via asmdef file, so they can be browse.
class DummyShaderLibrary
{
}

View File

@@ -0,0 +1,366 @@
#ifndef UNITY_ENTITY_LIGHTING_INCLUDED
#define UNITY_ENTITY_LIGHTING_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#define LIGHTMAP_RGBM_MAX_GAMMA real(5.0) // NB: Must match value in RGBMRanges.h
#define LIGHTMAP_RGBM_MAX_LINEAR real(34.493242) // LIGHTMAP_RGBM_MAX_GAMMA ^ 2.2
#ifdef UNITY_LIGHTMAP_RGBM_ENCODING
#ifdef UNITY_COLORSPACE_GAMMA
#define LIGHTMAP_HDR_MULTIPLIER LIGHTMAP_RGBM_MAX_GAMMA
#define LIGHTMAP_HDR_EXPONENT real(1.0) // Not used in gamma color space
#else
#define LIGHTMAP_HDR_MULTIPLIER LIGHTMAP_RGBM_MAX_LINEAR
#define LIGHTMAP_HDR_EXPONENT real(2.2)
#endif
#elif defined(UNITY_LIGHTMAP_DLDR_ENCODING)
#ifdef UNITY_COLORSPACE_GAMMA
#define LIGHTMAP_HDR_MULTIPLIER real(2.0)
#else
#define LIGHTMAP_HDR_MULTIPLIER real(4.59) // 2.0 ^ 2.2
#endif
#define LIGHTMAP_HDR_EXPONENT real(0.0)
#else // (UNITY_LIGHTMAP_FULL_HDR)
#define LIGHTMAP_HDR_MULTIPLIER real(1.0)
#define LIGHTMAP_HDR_EXPONENT real(1.0)
#endif
// TODO: Check if PI is correctly handled!
// Ref: "Efficient Evaluation of Irradiance Environment Maps" from ShaderX 2
real3 SHEvalLinearL0L1(real3 N, real4 shAr, real4 shAg, real4 shAb)
{
real4 vA = real4(N, 1.0);
real3 x1;
// Linear (L1) + constant (L0) polynomial terms
x1.r = dot(shAr, vA);
x1.g = dot(shAg, vA);
x1.b = dot(shAb, vA);
return x1;
}
real3 SHEvalLinearL2(real3 N, real4 shBr, real4 shBg, real4 shBb, real4 shC)
{
real3 x2;
// 4 of the quadratic (L2) polynomials
real4 vB = N.xyzz * N.yzzx;
x2.r = dot(shBr, vB);
x2.g = dot(shBg, vB);
x2.b = dot(shBb, vB);
// Final (5th) quadratic (L2) polynomial
real vC = N.x * N.x - N.y * N.y;
real3 x3 = shC.rgb * vC;
return x2 + x3;
}
#if HAS_HALF
half3 SampleSH9(half4 SHCoefficients[7], half3 N)
{
half4 shAr = SHCoefficients[0];
half4 shAg = SHCoefficients[1];
half4 shAb = SHCoefficients[2];
half4 shBr = SHCoefficients[3];
half4 shBg = SHCoefficients[4];
half4 shBb = SHCoefficients[5];
half4 shCr = SHCoefficients[6];
// Linear + constant polynomial terms
half3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
// Quadratic polynomials
res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return res;
}
#endif
float3 SampleSH9(float4 SHCoefficients[7], float3 N)
{
float4 shAr = SHCoefficients[0];
float4 shAg = SHCoefficients[1];
float4 shAb = SHCoefficients[2];
float4 shBr = SHCoefficients[3];
float4 shBg = SHCoefficients[4];
float4 shBb = SHCoefficients[5];
float4 shCr = SHCoefficients[6];
// Linear + constant polynomial terms
float3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
// Quadratic polynomials
res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return res;
}
// texture3dLod is not supported on gles2.
#if !defined(SHADER_API_GLES)
// This sample a 3D volume storing SH
// Volume is store as 3D texture with 4 R, G, B, Occ set of 4 coefficient store atlas in same 3D texture. Occ is use for occlusion.
// TODO: the packing here is inefficient as we will fetch values far away from each other and they may not fit into the cache - Suggest we pack RGB continuously
// TODO: The calcul of texcoord could be perform with a single matrix multicplication calcualted on C++ side that will fold probeVolumeMin and probeVolumeSizeInv into it and handle the identity case, no reasons to do it in C++ (ask Ionut about it)
// It should also handle the camera relative path (if the render pipeline use it)
// bakeDiffuseLighting and backBakeDiffuseLighting must be initialize outside the function
void SampleProbeVolumeSH4(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float3 backNormalWS, float4x4 WorldToTexture,
float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv,
inout float3 bakeDiffuseLighting, inout float3 backBakeDiffuseLighting)
{
float3 position = (transformToLocal == 1.0) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz;
// Each component is store in the same texture 3D. Each use one quater on the x axis
// Here we get R component then increase by step size (0.25) to get other component. This assume 4 component
// but last one is not used.
// Clamp to edge of the "internal" texture, as R is from half texel to size of R texture minus half texel.
// This avoid leaking
texCoord.x = clamp(texCoord.x * 0.25, 0.5 * texelSizeX, 0.25 - 0.5 * texelSizeX);
float4 shAr = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
texCoord.x += 0.25;
float4 shAg = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
texCoord.x += 0.25;
float4 shAb = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
bakeDiffuseLighting += SHEvalLinearL0L1(normalWS, shAr, shAg, shAb);
backBakeDiffuseLighting += SHEvalLinearL0L1(backNormalWS, shAr, shAg, shAb);
}
// Just a shortcut that call function above
float3 SampleProbeVolumeSH4(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture,
float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
{
float3 backNormalWSUnused = 0.0;
float3 bakeDiffuseLighting = 0.0;
float3 backBakeDiffuseLightingUnused = 0.0;
SampleProbeVolumeSH4(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), positionWS, normalWS, backNormalWSUnused, WorldToTexture,
transformToLocal, texelSizeX, probeVolumeMin, probeVolumeSizeInv,
bakeDiffuseLighting, backBakeDiffuseLightingUnused);
return bakeDiffuseLighting;
}
// The SphericalHarmonicsL2 coefficients are packed into 7 coefficients per color channel instead of 9.
// The packing from 9 to 7 is done from engine code and will use the alpha component of the pixel to store an additional SH coefficient.
// The 3D atlas texture will contain 7 SH coefficient parts.
// bakeDiffuseLighting and backBakeDiffuseLighting must be initialize outside the function
void SampleProbeVolumeSH9(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float3 backNormalWS, float4x4 WorldToTexture,
float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv,
inout float3 bakeDiffuseLighting, inout float3 backBakeDiffuseLighting)
{
float3 position = (transformToLocal == 1.0f) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv;
const uint shCoeffCount = 7;
const float invShCoeffCount = 1.0f / float(shCoeffCount);
// We need to compute proper X coordinate to sample into the atlas.
texCoord.x = texCoord.x / shCoeffCount;
// Clamp the x coordinate otherwise we'll have leaking between RGB coefficients.
float texCoordX = clamp(texCoord.x, 0.5f * texelSizeX, invShCoeffCount - 0.5f * texelSizeX);
float4 SHCoefficients[7];
for (uint i = 0; i < shCoeffCount; i++)
{
texCoord.x = texCoordX + i * invShCoeffCount;
SHCoefficients[i] = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
}
bakeDiffuseLighting += SampleSH9(SHCoefficients, normalize(normalWS));
backBakeDiffuseLighting += SampleSH9(SHCoefficients, normalize(backNormalWS));
}
// Just a shortcut that call function above
float3 SampleProbeVolumeSH9(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture,
float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
{
float3 backNormalWSUnused = 0.0;
float3 bakeDiffuseLighting = 0.0;
float3 backBakeDiffuseLightingUnused = 0.0;
SampleProbeVolumeSH9(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), positionWS, normalWS, backNormalWSUnused, WorldToTexture,
transformToLocal, texelSizeX, probeVolumeMin, probeVolumeSizeInv,
bakeDiffuseLighting, backBakeDiffuseLightingUnused);
return bakeDiffuseLighting;
}
#endif
float4 SampleProbeOcclusion(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float4x4 WorldToTexture,
float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
{
float3 position = (transformToLocal == 1.0) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz;
// Sample fourth texture in the atlas
// We need to compute proper U coordinate to sample.
// Clamp the coordinate otherwize we'll have leaking between ShB coefficients and Probe Occlusion(Occ) info
texCoord.x = max(texCoord.x * 0.25 + 0.75, 0.75 + 0.5 * texelSizeX);
return SAMPLE_TEXTURE3D(SHVolumeTexture, SHVolumeSampler, texCoord);
}
// Following functions are to sample enlighten lightmaps (or lightmaps encoded the same way as our
// enlighten implementation). They assume use of RGB9E5 for dynamic illuminance map and RGBM for baked ones.
// It is required for other platform that aren't supporting this format to implement variant of these functions
// (But these kind of platform should use regular render loop and not news shaders).
// TODO: This is the max value allowed for emissive (bad name - but keep for now to retrieve it) (It is 8^2.2 (gamma) and 8 is the limit of punctual light slider...), comme from UnityCg.cginc. Fix it!
// Ask Jesper if this can be change for HDRenderPipeline
#define EMISSIVE_RGBM_SCALE 97.0
// RGBM stuff is temporary. For now baked lightmap are in RGBM and the RGBM range for lightmaps is specific so we can't use the generic method.
// In the end baked lightmaps are going to be BC6H so the code will be the same as dynamic lightmaps.
// Same goes for emissive packed as an input for Enlighten with another hard coded multiplier.
// TODO: This function is used with the LightTransport pass to encode lightmap or emissive
real4 PackEmissiveRGBM(real3 rgb)
{
real kOneOverRGBMMaxRange = 1.0 / EMISSIVE_RGBM_SCALE;
const real kMinMultiplier = 2.0 * 1e-2;
real4 rgbm = real4(rgb * kOneOverRGBMMaxRange, 1.0);
rgbm.a = max(max(rgbm.r, rgbm.g), max(rgbm.b, kMinMultiplier));
rgbm.a = ceil(rgbm.a * 255.0) / 255.0;
// Division-by-zero warning from d3d9, so make compiler happy.
rgbm.a = max(rgbm.a, kMinMultiplier);
rgbm.rgb /= rgbm.a;
return rgbm;
}
real3 UnpackLightmapRGBM(real4 rgbmInput, real4 decodeInstructions)
{
#ifdef UNITY_COLORSPACE_GAMMA
return rgbmInput.rgb * (rgbmInput.a * decodeInstructions.x);
#else
return rgbmInput.rgb * (PositivePow(rgbmInput.a, decodeInstructions.y) * decodeInstructions.x);
#endif
}
real3 UnpackLightmapDoubleLDR(real4 encodedColor, real4 decodeInstructions)
{
return encodedColor.rgb * decodeInstructions.x;
}
real3 DecodeLightmap(real4 encodedIlluminance, real4 decodeInstructions)
{
#if defined(UNITY_LIGHTMAP_RGBM_ENCODING)
return UnpackLightmapRGBM(encodedIlluminance, decodeInstructions);
#elif defined(UNITY_LIGHTMAP_DLDR_ENCODING)
return UnpackLightmapDoubleLDR(encodedIlluminance, decodeInstructions);
#else // (UNITY_LIGHTMAP_FULL_HDR)
return encodedIlluminance.rgb;
#endif
}
real3 DecodeHDREnvironment(real4 encodedIrradiance, real4 decodeInstructions)
{
// Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels)
real alpha = max(decodeInstructions.w * (encodedIrradiance.a - 1.0) + 1.0, 0.0);
// If Linear mode is not supported we can skip exponent part
return (decodeInstructions.x * PositivePow(alpha, decodeInstructions.y)) * encodedIrradiance.rgb;
}
#if defined(UNITY_DOTS_INSTANCING_ENABLED)
#define TEXTURE2D_LIGHTMAP_PARAM TEXTURE2D_ARRAY_PARAM
#define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARRAY_ARGS
#define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D_ARRAY
#define LIGHTMAP_EXTRA_ARGS float2 uv, float slice
#define LIGHTMAP_EXTRA_ARGS_USE uv, slice
#else
#define TEXTURE2D_LIGHTMAP_PARAM TEXTURE2D_PARAM
#define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARGS
#define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D
#define LIGHTMAP_EXTRA_ARGS float2 uv
#define LIGHTMAP_EXTRA_ARGS_USE uv
#endif
real3 SampleSingleLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, bool encodedLightmap, real4 decodeInstructions)
{
// transform is scale and bias
uv = uv * transform.xy + transform.zw;
real3 illuminance = real3(0.0, 0.0, 0.0);
// Remark: baked lightmap is RGBM for now, dynamic lightmap is RGB9E5
if (encodedLightmap)
{
real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba;
illuminance = DecodeLightmap(encodedIlluminance, decodeInstructions);
}
else
{
illuminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgb;
}
return illuminance;
}
void SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform,
float3 normalWS, float3 backNormalWS, bool encodedLightmap, real4 decodeInstructions, inout real3 bakeDiffuseLighting, inout real3 backBakeDiffuseLighting)
{
// In directional mode Enlighten bakes dominant light direction
// in a way, that using it for half Lambert and then dividing by a "rebalancing coefficient"
// gives a result close to plain diffuse response lightmaps, but normalmapped.
// Note that dir is not unit length on purpose. Its length is "directionality", like
// for the directional specular lightmaps.
// transform is scale and bias
uv = uv * transform.xy + transform.zw;
real4 direction = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapDirTex, lightmapDirSampler, LIGHTMAP_EXTRA_ARGS_USE);
// Remark: baked lightmap is RGBM for now, dynamic lightmap is RGB9E5
real3 illuminance = real3(0.0, 0.0, 0.0);
if (encodedLightmap)
{
real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba;
illuminance = DecodeLightmap(encodedIlluminance, decodeInstructions);
}
else
{
illuminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgb;
}
real halfLambert = dot(normalWS, direction.xyz - 0.5) + 0.5;
bakeDiffuseLighting += illuminance * halfLambert / max(1e-4, direction.w);
real backHalfLambert = dot(backNormalWS, direction.xyz - 0.5) + 0.5;
backBakeDiffuseLighting += illuminance * backHalfLambert / max(1e-4, direction.w);
}
// Just a shortcut that call function above
real3 SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform,
float3 normalWS, bool encodedLightmap, real4 decodeInstructions)
{
float3 backNormalWSUnused = 0.0;
real3 bakeDiffuseLighting = 0.0;
real3 backBakeDiffuseLightingUnused = 0.0;
SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_ARGS(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS_USE, transform,
normalWS, backNormalWSUnused, encodedLightmap, decodeInstructions, bakeDiffuseLighting, backBakeDiffuseLightingUnused);
return bakeDiffuseLighting;
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_ENTITY_LIGHTING_INCLUDED

View File

@@ -0,0 +1,146 @@
#ifndef UNITY_FILTERING_INCLUDED
#define UNITY_FILTERING_INCLUDED
// Basic B-Spline of the 2nd degree (3rd order, support = 4).
// The fractional coordinate of each part is assumed to be in the [0, 1] range.
// https://www.desmos.com/calculator/479pgatwlt
//
// Sample use-case:
// float2 xy = uv * resolution.xy;
// float2 ic = floor(xy); // Note-centered (primal grid)
// float2 fc = 1 - frac(xy); // Inverse-translate the filter centered around 0.5
// Then pass x = fc.
//
real2 BSpline2Left(real2 x)
{
return 0.5 * x * x;
}
real2 BSpline2Middle(real2 x)
{
return (1 - x) * x + 0.5;
}
real2 BSpline2Right(real2 x)
{
return (0.5 * x - 1) * x + 0.5;
}
// Basic B-Spline of the 3nd degree (4th order, support = 4).
// The fractional coordinate of each part is assumed to be in the [0, 1] range.
// https://www.desmos.com/calculator/479pgatwlt
//
// Sample use-case:
// float2 xy = uv * resolution.xy;
// float2 ic = round(xy) + 0.5; // Cell-centered (dual grid)
// float2 fc = ic - xy; // Inverse-translate the the filter around 0.5 with a wrap
// Then pass x = fc.
//
real2 BSpline3Leftmost(real2 x)
{
return 0.16666667 * x * x * x;
}
real2 BSpline3MiddleLeft(real2 x)
{
return 0.16666667 + x * (0.5 + x * (0.5 - x * 0.5));
}
real2 BSpline3MiddleRight(real2 x)
{
return 0.66666667 + x * (-1.0 + 0.5 * x) * x;
}
real2 BSpline3Rightmost(real2 x)
{
return 0.16666667 + x * (-0.5 + x * (0.5 - x * 0.16666667));
}
// Compute weights & offsets for 4x bilinear taps for the bicubic B-Spline filter.
// The fractional coordinate should be in the [0, 1] range (centered on 0.5).
// Inspired by: http://vec3.ca/bicubic-filtering-in-fewer-taps/
void BicubicFilter(float2 fracCoord, out float2 weights[2], out float2 offsets[2])
{
float2 r = BSpline3Rightmost(fracCoord);
float2 mr = BSpline3MiddleRight(fracCoord);
float2 ml = BSpline3MiddleLeft(fracCoord);
float2 l = 1.0 - mr - ml - r;
weights[0] = r + mr;
weights[1] = ml + l;
offsets[0] = -1.0 + mr * rcp(weights[0]);
offsets[1] = 1.0 + l * rcp(weights[1]);
}
// Compute weights & offsets for 4x bilinear taps for the biquadratic B-Spline filter.
// The fractional coordinate should be in the [0, 1] range (centered on 0.5).
// Inspired by: http://vec3.ca/bicubic-filtering-in-fewer-taps/
void BiquadraticFilter(float2 fracCoord, out float2 weights[2], out float2 offsets[2])
{
float2 l = BSpline2Left(fracCoord);
float2 m = BSpline2Middle(fracCoord);
float2 r = 1.0 - l - m;
// Compute offsets for 4x bilinear taps for the quadratic B-Spline reconstruction kernel.
// 0: lerp between left and middle
// 1: lerp between middle and right
weights[0] = l + 0.5 * m;
weights[1] = r + 0.5 * m;
offsets[0] = -0.5 + 0.5 * m * rcp(weights[0]);
offsets[1] = 0.5 + r * rcp(weights[1]);
}
// texSize = (width, height, 1/width, 1/height)
float4 SampleTexture2DBiquadratic(TEXTURE2D_PARAM(tex, smp), float2 coord, float4 texSize)
{
float2 xy = coord * texSize.xy;
float2 ic = floor(xy);
float2 fc = frac(xy);
float2 weights[2], offsets[2];
BiquadraticFilter(1.0 - fc, weights, offsets); // Inverse-translate the filter centered around 0.5
// Apply the viewport scale right at the end.
return weights[0].x * weights[0].y * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[0].x, offsets[0].y)) * (texSize.zw * 1.0), 1.0), 0.0) // Top left
+ weights[1].x * weights[0].y * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[1].x, offsets[0].y)) * (texSize.zw * 1.0), 1.0), 0.0) // Top right
+ weights[0].x * weights[1].y * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[0].x, offsets[1].y)) * (texSize.zw * 1.0), 1.0), 0.0) // Bottom left
+ weights[1].x * weights[1].y * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[1].x, offsets[1].y)) * (texSize.zw * 1.0), 1.0), 0.0); // Bottom right
}
// texSize = (width, height, 1/width, 1/height)
float4 SampleTexture2DBicubic(TEXTURE2D_PARAM(tex, smp), float2 coord, float4 texSize, float2 maxCoord, uint unused /* needed to match signature of texarray version below */)
{
float2 xy = coord * texSize.xy + 0.5;
float2 ic = floor(xy);
float2 fc = frac(xy);
float2 weights[2], offsets[2];
BicubicFilter(fc, weights, offsets);
return weights[0].y * (weights[0].x * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[0].x, offsets[0].y) - 0.5) * texSize.zw, maxCoord), 0.0) +
weights[1].x * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[1].x, offsets[0].y) - 0.5) * texSize.zw, maxCoord), 0.0)) +
weights[1].y * (weights[0].x * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[0].x, offsets[1].y) - 0.5) * texSize.zw, maxCoord), 0.0) +
weights[1].x * SAMPLE_TEXTURE2D_LOD(tex, smp, min((ic + float2(offsets[1].x, offsets[1].y) - 0.5) * texSize.zw, maxCoord), 0.0));
}
#if !defined(SHADER_API_GLES)
// texSize = (width, height, 1/width, 1/height)
// texture array version for XR single-pass
float4 SampleTexture2DBicubic(TEXTURE2D_ARRAY_PARAM(tex, smp), float2 coord, float4 texSize, float2 maxCoord, uint slice)
{
float2 xy = coord * texSize.xy + 0.5;
float2 ic = floor(xy);
float2 fc = frac(xy);
float2 weights[2], offsets[2];
BicubicFilter(fc, weights, offsets);
return weights[0].y * (weights[0].x * SAMPLE_TEXTURE2D_ARRAY_LOD(tex, smp, min((ic + float2(offsets[0].x, offsets[0].y) - 0.5) * texSize.zw, maxCoord), slice, 0.0) +
weights[1].x * SAMPLE_TEXTURE2D_ARRAY_LOD(tex, smp, min((ic + float2(offsets[1].x, offsets[0].y) - 0.5) * texSize.zw, maxCoord), slice, 0.0)) +
weights[1].y * (weights[0].x * SAMPLE_TEXTURE2D_ARRAY_LOD(tex, smp, min((ic + float2(offsets[0].x, offsets[1].y) - 0.5) * texSize.zw, maxCoord), slice, 0.0) +
weights[1].x * SAMPLE_TEXTURE2D_ARRAY_LOD(tex, smp, min((ic + float2(offsets[1].x, offsets[1].y) - 0.5) * texSize.zw, maxCoord), slice, 0.0));
}
#else
#define SampleTexture2DBicubic ERROR_ON_UNSUPPORTED_FUNCTION(SampleTexture2DBicubic)
#endif
#endif // UNITY_FILTERING_INCLUDED

View File

@@ -0,0 +1,297 @@
#ifndef UNITY_GEOMETRICTOOLS_INCLUDED
#define UNITY_GEOMETRICTOOLS_INCLUDED
//-----------------------------------------------------------------------------
// Transform functions
//-----------------------------------------------------------------------------
// Rotate around a pivot point and an axis
float3 Rotate(float3 pivot, float3 position, float3 rotationAxis, float angle)
{
rotationAxis = normalize(rotationAxis);
float3 cpa = pivot + rotationAxis * dot(rotationAxis, position - pivot);
return cpa + ((position - cpa) * cos(angle) + cross(rotationAxis, (position - cpa)) * sin(angle));
}
float3x3 RotationFromAxisAngle(float3 A, float sinAngle, float cosAngle)
{
float c = cosAngle;
float s = sinAngle;
return float3x3(A.x * A.x * (1 - c) + c, A.x * A.y * (1 - c) - A.z * s, A.x * A.z * (1 - c) + A.y * s,
A.x * A.y * (1 - c) + A.z * s, A.y * A.y * (1 - c) + c, A.y * A.z * (1 - c) - A.x * s,
A.x * A.z * (1 - c) - A.y * s, A.y * A.z * (1 - c) + A.x * s, A.z * A.z * (1 - c) + c);
}
//-----------------------------------------------------------------------------
// Solver
//-----------------------------------------------------------------------------
// Solves the quadratic equation of the form: a*t^2 + b*t + c = 0.
// Returns 'false' if there are no real roots, 'true' otherwise.
// Ensures that roots.x <= roots.y.
bool SolveQuadraticEquation(float a, float b, float c, out float2 roots)
{
float det = Sq(b) - 4.0 * a * c;
float sqrtDet = sqrt(det);
roots.x = (-b - sign(a) * sqrtDet) / (2.0 * a);
roots.y = (-b + sign(a) * sqrtDet) / (2.0 * a);
return (det >= 0.0);
}
//-----------------------------------------------------------------------------
// Intersection functions
//-----------------------------------------------------------------------------
bool IntersectRayAABB(float3 rayOrigin, float3 rayDirection,
float3 boxMin, float3 boxMax,
float tMin, float tMax,
out float tEntr, out float tExit)
{
// Could be precomputed. Clamp to avoid INF. clamp() is a single ALU on GCN.
// rcp(FLT_EPS) = 16,777,216, which is large enough for our purposes,
// yet doesn't cause a lot of numerical issues associated with FLT_MAX.
float3 rayDirInv = clamp(rcp(rayDirection), -rcp(FLT_EPS), rcp(FLT_EPS));
// Perform ray-slab intersection (component-wise).
float3 t0 = boxMin * rayDirInv - (rayOrigin * rayDirInv);
float3 t1 = boxMax * rayDirInv - (rayOrigin * rayDirInv);
// Find the closest/farthest distance (component-wise).
float3 tSlabEntr = min(t0, t1);
float3 tSlabExit = max(t0, t1);
// Find the farthest entry and the nearest exit.
tEntr = Max3(tSlabEntr.x, tSlabEntr.y, tSlabEntr.z);
tExit = Min3(tSlabExit.x, tSlabExit.y, tSlabExit.z);
// Clamp to the range.
tEntr = max(tEntr, tMin);
tExit = min(tExit, tMax);
return tEntr < tExit;
}
// This simplified version assume that we care about the result only when we are inside the box
float IntersectRayAABBSimple(float3 start, float3 dir, float3 boxMin, float3 boxMax)
{
float3 invDir = rcp(dir);
// Find the ray intersection with box plane
float3 rbmin = (boxMin - start) * invDir;
float3 rbmax = (boxMax - start) * invDir;
float3 rbminmax = (dir > 0.0) ? rbmax : rbmin;
return min(min(rbminmax.x, rbminmax.y), rbminmax.z);
}
// Assume Sphere is at the origin (i.e start = position - spherePosition)
bool IntersectRaySphere(float3 start, float3 dir, float radius, out float2 intersections)
{
float a = dot(dir, dir);
float b = dot(dir, start) * 2.0;
float c = dot(start, start) - radius * radius;
return SolveQuadraticEquation(a, b, c, intersections);
}
// This simplified version assume that we care about the result only when we are inside the sphere
// Assume Sphere is at the origin (i.e start = position - spherePosition) and dir is normalized
// Ref: http://http.developer.nvidia.com/GPUGems/gpugems_ch19.html
float IntersectRaySphereSimple(float3 start, float3 dir, float radius)
{
float b = dot(dir, start) * 2.0;
float c = dot(start, start) - radius * radius;
float discriminant = b * b - 4.0 * c;
return abs(sqrt(discriminant) - b) * 0.5;
}
float3 IntersectRayPlane(float3 rayOrigin, float3 rayDirection, float3 planeOrigin, float3 planeNormal)
{
float dist = dot(planeNormal, planeOrigin - rayOrigin) / dot(planeNormal, rayDirection);
return rayOrigin + rayDirection * dist;
}
// Same as above but return intersection distance and true / false if the ray hit/miss
bool IntersectRayPlane(float3 rayOrigin, float3 rayDirection, float3 planePosition, float3 planeNormal, out float t)
{
bool res = false;
t = -1.0;
float denom = dot(planeNormal, rayDirection);
if (abs(denom) > 1e-5)
{
float3 d = planePosition - rayOrigin;
t = dot(d, planeNormal) / denom;
res = (t >= 0);
}
return res;
}
// Can support cones with an elliptic base: pre-scale 'coneAxisX' and 'coneAxisY' by (h/r_x) and (h/r_y).
// Returns parametric distances 'tEntr' and 'tExit' along the ray,
// subject to constraints 'tMin' and 'tMax'.
bool IntersectRayCone(float3 rayOrigin, float3 rayDirection,
float3 coneOrigin, float3 coneDirection,
float3 coneAxisX, float3 coneAxisY,
float tMin, float tMax,
out float tEntr, out float tExit)
{
// Inverse transform the ray into a coordinate system with the cone at the origin facing along the Z axis.
float3x3 rotMat = float3x3(coneAxisX, coneAxisY, coneDirection);
float3 o = mul(rotMat, rayOrigin - coneOrigin);
float3 d = mul(rotMat, rayDirection);
// Cone equation (facing along Z): (h/r*x)^2 + (h/r*y)^2 - z^2 = 0.
// Cone axes are premultiplied with (h/r).
// Set up the quadratic equation: a*t^2 + b*t + c = 0.
float a = d.x * d.x + d.y * d.y - d.z * d.z;
float b = o.x * d.x + o.y * d.y - o.z * d.z;
float c = o.x * o.x + o.y * o.y - o.z * o.z;
float2 roots;
// Check whether we have at least 1 root.
bool hit = SolveQuadraticEquation(a, 2 * b, c, roots);
tEntr = roots.x;
tExit = roots.y;
float3 pEntr = o + tEntr * d;
float3 pExit = o + tExit * d;
// Clip the negative cone.
bool pEntrNeg = pEntr.z < 0;
bool pExitNeg = pExit.z < 0;
if (pEntrNeg && pExitNeg) { hit = false; }
if (pEntrNeg) { tEntr = tExit; tExit = tMax; }
if (pExitNeg) { tExit = tEntr; tEntr = tMin; }
// Clamp using the values passed into the function.
tEntr = clamp(tEntr, tMin, tMax);
tExit = clamp(tExit, tMin, tMax);
// Check for grazing intersections.
if (tEntr == tExit) { hit = false; }
return hit;
}
bool IntersectSphereAABB(float3 position, float radius, float3 aabbMin, float3 aabbMax)
{
float x = max(aabbMin.x, min(position.x, aabbMax.x));
float y = max(aabbMin.y, min(position.y, aabbMax.y));
float z = max(aabbMin.z, min(position.z, aabbMax.z));
float distance2 = ((x - position.x) * (x - position.x) + (y - position.y) * (y - position.y) + (z - position.z) * (z - position.z));
return distance2 < radius * radius;
}
//-----------------------------------------------------------------------------
// Miscellaneous functions
//-----------------------------------------------------------------------------
// Box is AABB
float DistancePointBox(float3 position, float3 boxMin, float3 boxMax)
{
return length(max(max(position - boxMax, boxMin - position), float3(0.0, 0.0, 0.0)));
}
float3 ProjectPointOnPlane(float3 position, float3 planePosition, float3 planeNormal)
{
return position - (dot(position - planePosition, planeNormal) * planeNormal);
}
// Plane equation: {(a, b, c) = N, d = -dot(N, P)}.
// Returns the distance from the plane to the point 'p' along the normal.
// Positive -> in front (above), negative -> behind (below).
float DistanceFromPlane(float3 p, float4 plane)
{
return dot(float4(p, 1.0), plane);
}
// Returns 'true' if the triangle is outside of the frustum.
// 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
bool CullTriangleFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
{
bool outside = false;
for (int i = 0; i < numPlanes; i++)
{
// If all 3 points are behind any of the planes, we cull.
outside = outside || Max3(DistanceFromPlane(p0, frustumPlanes[i]),
DistanceFromPlane(p1, frustumPlanes[i]),
DistanceFromPlane(p2, frustumPlanes[i])) < epsilon;
}
return outside;
}
// Returns 'true' if the edge of the triangle is outside of the frustum.
// The edges are defined s.t. they are on the opposite side of the point with the given index.
// 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
//output packing:
// x,y,z - one component per triangle edge, true if outside, false otherwise
// w - true if entire triangle is outside of at least 1 plane of the frustum, false otherwise
bool4 CullFullTriangleAndEdgesFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
{
bool4 edgesOutsideXYZ_triangleOutsideW = false;
for (int i = 0; i < numPlanes; i++)
{
bool3 pointsOutside = bool3(DistanceFromPlane(p0, frustumPlanes[i]) < epsilon,
DistanceFromPlane(p1, frustumPlanes[i]) < epsilon,
DistanceFromPlane(p2, frustumPlanes[i]) < epsilon);
bool3 edgesOutside;
// If both points of the edge are behind any of the planes, we cull.
edgesOutside.x = pointsOutside.y && pointsOutside.z;
edgesOutside.y = pointsOutside.x && pointsOutside.z;
edgesOutside.z = pointsOutside.x && pointsOutside.y;
edgesOutsideXYZ_triangleOutsideW = edgesOutsideXYZ_triangleOutsideW || bool4(edgesOutside.xyz, all(pointsOutside));
}
return edgesOutsideXYZ_triangleOutsideW;
}
// Returns 'true' if the edge of the triangle is outside of the frustum.
// The edges are defined s.t. they are on the opposite side of the point with the given index.
// 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
//output packing:
// x,y,z - one component per triangle edge, true if outside, false otherwise
bool3 CullTriangleEdgesFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
{
return CullFullTriangleAndEdgesFrustum(p0, p1, p2, epsilon, frustumPlanes, numPlanes).xyz;
}
bool CullTriangleBackFaceView(float3 p0, float3 p1, float3 p2, float epsilon, float3 V, float winding)
{
float3 edge1 = p1 - p0;
float3 edge2 = p2 - p0;
float3 N = cross(edge1, edge2);
float NdotV = dot(N, V) * winding;
// Optimize:
// NdotV / (length(N) * length(V)) < Epsilon
// NdotV < Epsilon * length(N) * length(V)
// NdotV < Epsilon * sqrt(dot(N, N)) * sqrt(dot(V, V))
// NdotV < Epsilon * sqrt(dot(N, N) * dot(V, V))
return NdotV < epsilon * sqrt(dot(N, N) * dot(V, V));
}
// Returns 'true' if a triangle defined by 3 vertices is back-facing.
// 'epsilon' is the (negative) value of dot(N, V) below which we cull the triangle.
// 'winding' can be used to change the order: pass 1 for (p0 -> p1 -> p2), or -1 for (p0 -> p2 -> p1).
bool CullTriangleBackFace(float3 p0, float3 p1, float3 p2, float epsilon, float3 viewPos, float winding)
{
float3 V = viewPos - p0;
return CullTriangleBackFaceView(p0, p1, p2, epsilon, V, winding);
}
#endif // UNITY_GEOMETRICTOOLS_INCLUDED

View File

@@ -0,0 +1,864 @@
#ifndef GRA_HLSL_3
#define GRA_HLSL_3 0
#endif
#ifndef GRA_HLSL_4
#define GRA_HLSL_4 0
#endif
#ifndef GRA_HLSL_5
#define GRA_HLSL_5 0
#endif
#ifndef GRA_GLSL_120
#define GRA_GLSL_120 0
#endif
#ifndef GRA_GLSL_130
#define GRA_GLSL_130 0
#endif
#ifndef GRA_GLSL_330
#define GRA_GLSL_330 0
#endif
#ifndef GRA_VERTEX_SHADER
#define GRA_VERTEX_SHADER 0
#endif
#ifndef GRA_PIXEL_SHADER
#define GRA_PIXEL_SHADER 0
#endif
#ifndef GRA_HQ_CUBEMAPPING
#define GRA_HQ_CUBEMAPPING 0
#endif
#ifndef GRA_DEBUG_TILES
#define GRA_DEBUG_TILES 0
#endif
#ifndef GRA_BGRA
#define GRA_BGRA 0
#endif
#ifndef GRA_ROW_MAJOR
#define GRA_ROW_MAJOR 1
#endif
#ifndef GRA_DEBUG
#define GRA_DEBUG 1
#endif
#ifndef GRA_64BIT_RESOLVER
#define GRA_64BIT_RESOLVER 0
#endif
#ifndef GRA_RWTEXTURE2D_SCALE
#define GRA_RWTEXTURE2D_SCALE 16
#endif
#ifndef GRA_DISABLE_TEX_LOAD
#define GRA_DISABLE_TEX_LOAD 0
#endif
#ifndef GRA_PACK_RESOLVE_OUTPUT
#define GRA_PACK_RESOLVE_OUTPUT 1
#endif
// Temp workaround for some platforms's lack of unorm.
#ifdef GRA_NO_UNORM
#define GRA_UNORM
#else
#define GRA_UNORM unorm
#endif
#ifndef GRA_TEXTURE_ARRAY_SUPPORT
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1) || (GRA_GLSL_330 == 1)
#define GRA_TEXTURE_ARRAY_SUPPORT 1
#else
#define GRA_TEXTURE_ARRAY_SUPPORT 0
#endif
#endif
#define GRA_HLSL_FAMILY ((GRA_HLSL_3 == 1) || (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1))
#define GRA_GLSL_FAMILY ((GRA_GLSL_120 == 1) || (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1))
#if GRA_HLSL_FAMILY
#define gra_Float2 float2
#define gra_Float3 float3
#define gra_Float4 float4
#define gra_Int3 int3
#define gra_Float4x4 float4x4
#define gra_Unroll [unroll]
#define gra_Branch [branch]
#elif GRA_GLSL_FAMILY
#if (GRA_VERTEX_SHADER == 0) && (GRA_PIXEL_SHADER ==0)
#error GLSL requires knowledge of the shader stage! Neither GRA_VERTEX_SHADER or GRA_PIXEL_SHADER are defined!
#else
#define gra_Float2 vec2
#define gra_Float3 vec3
#define gra_Float4 vec4
#define gra_Int3 ivec3
#define gra_Float4x4 mat4
#define gra_Unroll
#define gra_Branch
#if (GRA_VERTEX_SHADER == 1)
#define ddx
#define ddy
#elif (GRA_PIXEL_SHADER == 1)
#define ddx dFdx
#define ddy dFdy
#endif
#define frac fract
#define lerp mix
/** This is not correct (http://stackoverflow.com/questions/7610631/glsl-mod-vs-hlsl-fmod) but it is for our case */
#define fmod mod
#endif
#else
#error unknown shader architecture
#endif
#if (GRA_DISABLE_TEX_LOAD!=1)
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1) || (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1)
#define GRA_LOAD_INSTR 1
#else
#define GRA_LOAD_INSTR 0
#endif
#else
#define GRA_LOAD_INSTR 0
#endif
/**
a cross API texture handle
*/
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
struct GraniteTranslationTexture
{
SamplerState Sampler;
Texture2D Texture;
};
struct GraniteCacheTexture
{
SamplerState Sampler;
#if GRA_TEXTURE_ARRAY_SUPPORT
Texture2DArray TextureArray;
#else
Texture2D Texture;
#endif
};
#elif (GRA_HLSL_3 == 1) || (GRA_GLSL_120 == 1) || (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1)
#define GraniteTranslationTexture sampler2D
#if GRA_TEXTURE_ARRAY_SUPPORT
#define GraniteCacheTexture sampler2DArray
#else
#define GraniteCacheTexture sampler2D
#endif
#else
#error unknow shader archtecture
#endif
/**
Struct defining the constant buffer for each streaming texture.
Use IStreamingTexture::GetConstantBuffer to fill this struct.
*/
struct GraniteStreamingTextureConstantBuffer
{
#define _grStreamingTextureCBSize 2
gra_Float4 data[_grStreamingTextureCBSize];
};
/**
Struct defining the constant buffer for each cube streaming texture.
Use multiple calls to IStreamingTexture::GetConstantBuffer this struct (one call for each face).
*/
struct GraniteStreamingTextureCubeConstantBuffer
{
#define _grStreamingTextureCubeCBSize 6
GraniteStreamingTextureConstantBuffer data[_grStreamingTextureCubeCBSize];
};
/**
Struct defining the constant buffer for each tileset.
Use ITileSet::GetConstantBuffer to fill this struct.
*/
struct GraniteTilesetConstantBuffer
{
#define _grTilesetCBSize 2
gra_Float4x4 data[_grTilesetCBSize];
};
/**
Utility struct used by the shaderlib to wrap up all required constant buffers needed to perform a VT lookup/sample.
*/
struct GraniteConstantBuffers
{
GraniteTilesetConstantBuffer tilesetBuffer;
GraniteStreamingTextureConstantBuffer streamingTextureBuffer;
};
/**
Utility struct used by the shaderlib to wrap up all required constant buffers needed to perform a Cube VT lookup/sample.
*/
struct GraniteCubeConstantBuffers
{
GraniteTilesetConstantBuffer tilesetBuffer;
GraniteStreamingTextureCubeConstantBuffer streamingTextureCubeBuffer;
};
/**
The Granite lookup data for the different sampling functions.
*/
// Granite lookup data for automatic mip level selecting sampling
struct GraniteLookupData
{
gra_Float4 translationTableData;
gra_Float2 textureCoordinates;
gra_Float2 dX;
gra_Float2 dY;
};
// Granite lookup data for explicit level-of-detail sampling
struct GraniteLODLookupData
{
gra_Float4 translationTableData;
gra_Float2 textureCoordinates;
float cacheLevel;
};
//@IGNORE_END
// public interface
/*
END OF PUBLIC INTERFACE
Everything below this point should be treated as private to GraniteShaderLib.h
*/
//@INSERT_DEFINES
#define gra_TilesetBuffer grCB.tilesetBuffer
#define gra_TilesetBufferInternal tsCB.data[0]
#define gra_TilesetCacheBuffer tsCB.data[1]
#define gra_StreamingTextureCB grCB.streamingTextureBuffer
#define gra_StreamingTextureCubeCB grCB.streamingTextureCubeBuffer
#define gra_Transform grCB.streamingTextureBuffer.data[0]
#define gra_CubeTransform grCB.streamingTextureCubeBuffer.data
#define gra_StreamingTextureTransform grSTCB.data[0]
#define gra_StreamingTextureInfo grSTCB.data[1]
#define gra_NumLevels gra_StreamingTextureInfo.x
#define gra_AssetWidthRcp gra_StreamingTextureInfo.y
#define gra_AssetHeightRcp gra_StreamingTextureInfo.z
#if GRA_ROW_MAJOR == 1
#define gra_TranslationTableBias gra_TilesetBufferInternal[0][0]
#define gra_MaxAnisotropyLog2 gra_TilesetBufferInternal[1][0]
#define gra_CalcMiplevelDeltaScale gra_Float2(gra_TilesetBufferInternal[2][0], gra_TilesetBufferInternal[3][0])
#define gra_CalcMiplevelDeltaScaleX gra_TilesetBufferInternal[2][0]
#define gra_CalcMiplevelDeltaScaleY gra_TilesetBufferInternal[3][0]
#define gra_LodBiasPow2 gra_TilesetBufferInternal[0][1]
#define gra_TrilinearOffset gra_TilesetBufferInternal[0][2]
#define gra_TileContentInTiles gra_Float2(gra_TilesetBufferInternal[0][2], gra_TilesetBufferInternal[1][2])
#define gra_Level0NumTilesX gra_TilesetBufferInternal[0][3]
#define gra_NumTilesYScale gra_TilesetBufferInternal[1][3]
#define gra_TextureMagic gra_TilesetBufferInternal[2][3]
#define gra_TextureId gra_TilesetBufferInternal[3][3]
#define gra_RcpCacheInTiles(l) gra_Float2(gra_TilesetCacheBuffer[0][l], gra_TilesetCacheBuffer[1][l])
#define gra_BorderPixelsRcpCache(l) gra_Float2(gra_TilesetCacheBuffer[2][l], gra_TilesetCacheBuffer[3][l])
#else
#define gra_TranslationTableBias gra_TilesetBufferInternal[0][0]
#define gra_MaxAnisotropyLog2 gra_TilesetBufferInternal[0][1]
#define gra_CalcMiplevelDeltaScale gra_Float2(gra_TilesetBufferInternal[0][2], gra_TilesetBufferInternal[0][3])
#define gra_CalcMiplevelDeltaScaleX gra_TilesetBufferInternal[0][2]
#define gra_CalcMiplevelDeltaScaleY gra_TilesetBufferInternal[0][3]
#define gra_LodBiasPow2 gra_TilesetBufferInternal[1][0]
#define gra_TrilinearOffset gra_TilesetBufferInternal[2][0]
#define gra_TileContentInTiles gra_Float2(gra_TilesetBufferInternal[2][0], gra_TilesetBufferInternal[2][1])
#define gra_Level0NumTilesX gra_TilesetBufferInternal[3][0]
#define gra_NumTilesYScale gra_TilesetBufferInternal[3][1]
#define gra_TextureMagic gra_TilesetBufferInternal[3][2]
#define gra_TextureId gra_TilesetBufferInternal[3][3]
#define gra_RcpCacheInTiles(l) gra_Float2(gra_TilesetCacheBuffer[l][0], gra_TilesetCacheBuffer[l][1])
#define gra_BorderPixelsRcpCache(l) gra_Float2(gra_TilesetCacheBuffer[l][2], gra_TilesetCacheBuffer[l][3])
#endif
#if (GRA_GLSL_120==1)
// Extension needed for texture2DLod
//extension GL_ARB_shader_texture_lod : enable
// Extensions needed fot texture2DGrad
//extension GL_EXT_gpu_shader4 : enable
// Extensions needed for bit manipulation
//extension GL_ARB_shader_bit_encoding : enable
#endif
#if (GRA_TEXTURE_ARRAY_SUPPORT==1)
gra_Float4 GranitePrivate_SampleArray(in GraniteCacheTexture tex, in gra_Float3 texCoord)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.TextureArray.Sample(tex.Sampler, texCoord);
#elif (GRA_GLSL_330 == 1)
return texture(tex, texCoord);
#else
#error using unsupported function
#endif
}
gra_Float4 GranitePrivate_SampleGradArray(in GraniteCacheTexture tex, in gra_Float3 texCoord, in gra_Float2 dX, in gra_Float2 dY)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.TextureArray.SampleGrad(tex.Sampler,texCoord,dX,dY);
#elif (GRA_GLSL_330 == 1)
return textureGrad(tex, texCoord, dX, dY);
#else
#error using unsupported function
#endif
}
gra_Float4 GranitePrivate_SampleLevelArray(in GraniteCacheTexture tex, in gra_Float3 texCoord, in float level)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.TextureArray.SampleLevel(tex.Sampler, texCoord, level);
#elif (GRA_GLSL_330 == 1)
return textureLod(tex, texCoord, level);
#else
#error using unsupported function
#endif
}
#else
gra_Float4 GranitePrivate_Sample(in GraniteCacheTexture tex, in gra_Float2 texCoord)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.Texture.Sample(tex.Sampler,texCoord);
#elif (GRA_HLSL_3 == 1)
return tex2D(tex,texCoord);
#elif (GRA_GLSL_120 == 1) || (GRA_GLSL_130 == 1)
return texture2D(tex, texCoord);
#elif (GRA_GLSL_330 == 1)
return texture(tex, texCoord);
#endif
}
gra_Float4 GranitePrivate_SampleLevel(in GraniteCacheTexture tex, in gra_Float2 texCoord, in float level)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.Texture.SampleLevel(tex.Sampler, texCoord, level);
#elif (GRA_HLSL_3 == 1)
return tex2Dlod(tex,gra_Float4(texCoord,0.0,level));
#elif (GRA_GLSL_120 == 1)
return texture2DLod(tex, texCoord, level);
#elif (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1)
return textureLod(tex, texCoord, level);
#endif
}
gra_Float4 GranitePrivate_SampleGrad(in GraniteCacheTexture tex, in gra_Float2 texCoord, in gra_Float2 dX, in gra_Float2 dY)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.Texture.SampleGrad(tex.Sampler,texCoord,dX,dY);
#elif (GRA_HLSL_3 == 1)
return tex2D(tex,texCoord,dX,dY);
#elif (GRA_GLSL_120 == 1)
return texture2DGrad(tex, texCoord, dX, dY);
#elif (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1)
return textureGrad(tex, texCoord, dX, dY);
#endif
}
#endif //#if (GRA_TEXTURE_ARRAY_SUPPORT==1)
#if (GRA_LOAD_INSTR==1)
gra_Float4 GranitePrivate_Load(in GraniteTranslationTexture tex, in gra_Int3 location)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.Texture.Load(location);
#elif (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1)
return texelFetch(tex, location.xy, location.z);
#elif (GRA_HLSL_3 == 1) || (GRA_GLSL_120 == 1)
#error using unsupported function
#endif
}
#endif
//work-around shader compiler bug
//compiler gets confused with GranitePrivate_SampleLevel taking a GraniteCacheTexture as argument when array support is disabled
//Without array support, GraniteCacheTexture and GraniteTranslationTexture are the same (but still different types!)
//compiler is confused (ERR_AMBIGUOUS_FUNCTION_CALL). Looks like somebody is over enthusiastic optimizing...
gra_Float4 GranitePrivate_SampleLevel_Translation(in GraniteTranslationTexture tex, in gra_Float2 texCoord, in float level)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return tex.Texture.SampleLevel(tex.Sampler, texCoord, level);
#elif (GRA_HLSL_3 == 1)
return tex2Dlod(tex,gra_Float4(texCoord,0.0,level));
#elif (GRA_GLSL_120 == 1)
return texture2DLod(tex, texCoord, level);
#elif (GRA_GLSL_130 == 1) || (GRA_GLSL_330 == 1)
return textureLod(tex, texCoord, level);
#endif
}
float GranitePrivate_Saturate(in float value)
{
#if GRA_HLSL_FAMILY
return saturate(value);
#elif GRA_GLSL_FAMILY
return clamp(value, 0.0f, 1.0f);
#endif
}
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1) || (GRA_GLSL_330 == 1)
uint GranitePrivate_FloatAsUint(float value)
{
#if (GRA_HLSL_5 == 1) || (GRA_HLSL_4 == 1)
return asuint(value);
#elif (GRA_GLSL_330 == 1)
return floatBitsToUint(value);
#endif
}
#endif
float GranitePrivate_Pow2(uint exponent)
{
#if GRA_HLSL_FAMILY
return pow(2.0, exponent);
#else
return pow(2.0, float(exponent));
#endif
}
gra_Float2 GranitePrivate_RepeatUV(in gra_Float2 uv, in GraniteStreamingTextureConstantBuffer grSTCB)
{
return frac(uv);
}
gra_Float2 GranitePrivate_UdimUV(in gra_Float2 uv, in GraniteStreamingTextureConstantBuffer grSTCB)
{
return uv;
}
gra_Float2 GranitePrivate_ClampUV(in gra_Float2 uv, in GraniteStreamingTextureConstantBuffer grSTCB)
{
gra_Float2 epsilon2 = gra_Float2(gra_AssetWidthRcp, gra_AssetHeightRcp);
return clamp(uv, epsilon2, gra_Float2(1,1) - epsilon2);
}
gra_Float2 GranitePrivate_MirrorUV(in gra_Float2 uv, in GraniteStreamingTextureConstantBuffer grSTCB)
{
gra_Float2 t = frac(uv*0.5)*2.0;
gra_Float2 l = gra_Float2(1.0,1.0);
return l-abs(t-l);
}
// function definitons for private functions
gra_Float4 GranitePrivate_PackTileId(in gra_Float2 tileXY, in float level, in float textureID);
gra_Float4 Granite_DebugPackedTileId64(in gra_Float4 PackedTile)
{
#if GRA_64BIT_RESOLVER
gra_Float4 output;
const float scale = 1.0f / 65535.0f;
gra_Float4 temp = PackedTile / scale;
output.x = fmod(temp.x, 256.0f);
output.y = floor(temp.x / 256.0f) + fmod(temp.y, 16.0f) * 16.0f;
output.z = floor(temp.y / 16.0f);
output.w = temp.z + temp.a * 16.0f;
return gra_Float4
(
(float)output.x / 255.0f,
(float)output.y / 255.0f,
(float)output.z / 255.0f,
(float)output.w / 255.0f
);
#else
return PackedTile;
#endif
}
gra_Float3 Granite_UnpackNormal(in gra_Float4 PackedNormal, float scale)
{
gra_Float2 reconstructed = gra_Float2(PackedNormal.x * PackedNormal.a, PackedNormal.y) * 2.0f - 1.0f;
reconstructed *= scale;
float z = sqrt(1.0f - GranitePrivate_Saturate(dot(reconstructed, reconstructed)));
return gra_Float3(reconstructed, z);
}
gra_Float3 Granite_UnpackNormal(in gra_Float4 PackedNormal)
{
return Granite_UnpackNormal(PackedNormal, 1.0);
}
#if GRA_HLSL_FAMILY
GraniteTilesetConstantBuffer Granite_ApplyResolutionOffset(in GraniteTilesetConstantBuffer INtsCB, in float resolutionOffsetPow2)
{
GraniteTilesetConstantBuffer tsCB = INtsCB;
gra_LodBiasPow2 *= resolutionOffsetPow2;
//resolutionOffsetPow2 *= resolutionOffsetPow2; //Square it before multiplying it in below
gra_CalcMiplevelDeltaScaleX *= resolutionOffsetPow2;
gra_CalcMiplevelDeltaScaleY *= resolutionOffsetPow2;
return tsCB;
}
GraniteTilesetConstantBuffer Granite_SetMaxAnisotropy(in GraniteTilesetConstantBuffer INtsCB, in float maxAnisotropyLog2)
{
GraniteTilesetConstantBuffer tsCB = INtsCB;
gra_MaxAnisotropyLog2 = min(gra_MaxAnisotropyLog2, maxAnisotropyLog2);
return tsCB;
}
#else
void Granite_ApplyResolutionOffset(inout GraniteTilesetConstantBuffer tsCB, in float resolutionOffsetPow2)
{
gra_LodBiasPow2 *= resolutionOffsetPow2;
//resolutionOffsetPow2 *= resolutionOffsetPow2; //Square it before multiplying it in below
gra_CalcMiplevelDeltaScaleX *= resolutionOffsetPow2;
gra_CalcMiplevelDeltaScaleY *= resolutionOffsetPow2;
}
void Granite_SetMaxAnisotropy(inout GraniteTilesetConstantBuffer tsCB, in float maxAnisotropyLog2)
{
gra_MaxAnisotropyLog2 = min(gra_MaxAnisotropyLog2, maxAnisotropyLog2);
}
#endif
gra_Float2 Granite_Transform(in GraniteStreamingTextureConstantBuffer grSTCB, in gra_Float2 textureCoord)
{
return textureCoord * gra_StreamingTextureTransform.zw + gra_StreamingTextureTransform.xy;
}
gra_Float4 Granite_MergeResolveOutputs(in gra_Float4 resolve0, in gra_Float4 resolve1, in gra_Float2 pixelLocation)
{
gra_Float2 screenPos = frac(pixelLocation * 0.5f);
bool dither = (screenPos.x != screenPos.y);
return (dither) ? resolve0 : resolve1;
}
gra_Float4 Granite_PackTileId(in gra_Float4 unpackedTileID)
{
return GranitePrivate_PackTileId(unpackedTileID.xy, unpackedTileID.z, unpackedTileID.w);
}
#if (GRA_HLSL_5 == 1)
void Granite_DitherResolveOutput(in gra_Float4 resolve, in RWTexture2D<GRA_UNORM gra_Float4> resolveTexture, in gra_Float2 screenPos, in float alpha)
{
const uint2 pixelPos = int2(screenPos);
const uint2 pixelLocation = pixelPos % GRA_RWTEXTURE2D_SCALE;
bool dither = (pixelLocation.x == 0) && (pixelLocation.y == 0);
uint2 writePos = pixelPos / GRA_RWTEXTURE2D_SCALE;
if ( alpha == 0 )
{
dither = false;
}
else if (alpha != 1.0)
{
// Do a 4x4 dither patern so alternating pixels resolve to the first or the second texture
gra_Float2 pixelLocationAlpha = frac(screenPos * 0.25f); // We don't scale after the frac so this will give coords 0, 0.25, 0.5, 0.75
int pixelId = (int)(pixelLocationAlpha.y * 16 + pixelLocationAlpha.x * 4); //faster as a dot2 ?
// Clamp
// This ensures that for example alpha=0.95 still resolves some tiles of the surfaces behind it
// and alpha=0.05 still resolves some tiles of this surface
alpha = min(max(alpha, 0.0625), 0.9375);
// Modern hardware supports array indexing with per pixel varying indexes
// on old hardware this will be expanded to a conditional tree by the compiler
const float thresholdMaxtrix[16] = { 1.0f / 17.0f, 9.0f / 17.0f, 3.0f / 17.0f, 11.0f / 17.0f,
13.0f / 17.0f, 5.0f / 17.0f, 15.0f / 17.0f, 7.0f / 17.0f,
4.0f / 17.0f, 12.0f / 17.0f, 2.0f / 17.0f, 10.0f / 17.0f,
16.0f / 17.0f, 8.0f / 17.0f, 14.0f / 17.0f, 6.0f / 17.0f};
float threshold = thresholdMaxtrix[pixelId];
if (alpha < threshold)
{
dither = false;
}
}
gra_Branch if (dither)
{
#if (GRA_PACK_RESOLVE_OUTPUT==0)
resolveTexture[writePos] = Granite_PackTileId(resolve);
#else
resolveTexture[writePos] = resolve;
#endif
}
}
#endif
float GranitePrivate_CalcMiplevelAnisotropic(in GraniteTilesetConstantBuffer tsCB, in GraniteStreamingTextureConstantBuffer grSTCB, in gra_Float2 ddxTc, in gra_Float2 ddyTc)
{
// Calculate the required mipmap level, this uses a similar
// formula as the GL spec.
// To reduce sqrt's and log2's we do some stuff in squared space here and further below in log space
// i.e. we wait with the sqrt untill we can do it for 'free' later during the log2
ddxTc *= gra_CalcMiplevelDeltaScale;
ddyTc *= gra_CalcMiplevelDeltaScale;
float lenDxSqr = dot(ddxTc, ddxTc);
float lenDySqr = dot(ddyTc, ddyTc);
float dMaxSqr = max(lenDxSqr, lenDySqr);
float dMinSqr = min(lenDxSqr, lenDySqr);
// Calculate mipmap levels directly from sqared distances. This uses log2(sqrt(x)) = 0.5 * log2(x) to save some sqrt's
float maxLevel = 0.5 * log2( dMaxSqr );
float minLevel = 0.5 * log2( dMinSqr );
// Calculate the log2 of the anisotropy and clamp it by the max supported. This uses log2(a/b) = log2(a)-log2(b) and min(log(a),log(b)) = log(min(a,b))
float anisoLog2 = maxLevel - minLevel;
anisoLog2 = min( anisoLog2, gra_MaxAnisotropyLog2 );
// Adjust for anisotropy & clamp to level 0
float result = max(maxLevel - anisoLog2 - 0.5f, 0.0f); //Subtract 0.5 to compensate for trilinear mipmapping
// Added clamping to avoid "hot pink" on small tilesets that try to sample past the 1x1 tile miplevel
// This happens if you for example import a relatively small texture and zoom out
return min(result, gra_NumLevels);
}
float GranitePrivate_CalcMiplevelLinear(in GraniteTilesetConstantBuffer tsCB, in GraniteStreamingTextureConstantBuffer grSTCB, in gra_Float2 ddxTc, in gra_Float2 ddyTc)
{
// Calculate the required mipmap level, this uses a similar
// formula as the GL spec.
// To reduce sqrt's and log2's we do some stuff in squared space here and further below in log space
// i.e. we wait with the sqrt untill we can do it for 'free' later during the log2
ddxTc *= gra_CalcMiplevelDeltaScale;
ddyTc *= gra_CalcMiplevelDeltaScale;
float lenDxSqr = dot(ddxTc, ddxTc);
float lenDySqr = dot(ddyTc, ddyTc);
float dMaxSqr = max(lenDxSqr, lenDySqr);
// Calculate mipmap levels directly from squared distances. This uses log2(sqrt(x)) = 0.5 * log2(x) to save some sqrt's
float maxLevel = 0.5 * log2(dMaxSqr) - 0.5f; //Subtract 0.5 to compensate for trilinear mipmapping
return clamp(maxLevel, 0.0f, gra_NumLevels);
}
gra_Float4 GranitePrivate_PackTileId(in gra_Float2 tileXY, in float level, in float textureID)
{
#if GRA_64BIT_RESOLVER == 0
gra_Float4 resultBits;
resultBits.x = fmod(tileXY.x, 256.0f);
resultBits.y = floor(tileXY.x / 256.0f) + fmod(tileXY.y, 32.0f) * 8.0f;
resultBits.z = floor(tileXY.y / 32.0f) + fmod(level, 4.0f) * 64.0f;
resultBits.w = floor(level / 4.0f) + textureID * 4.0f;
const float scale = 1.0f / 255.0f;
#if GRA_BGRA == 0
return scale * gra_Float4
(
float(resultBits.x),
float(resultBits.y),
float(resultBits.z),
float(resultBits.w)
);
#else
return scale * gra_Float4
(
float(resultBits.z),
float(resultBits.y),
float(resultBits.x),
float(resultBits.w)
);
#endif
#else
const float scale = 1.0f / 65535.0f;
return gra_Float4(tileXY.x, tileXY.y, level, textureID) * scale;
#endif
}
gra_Float4 GranitePrivate_UnpackTileId(in gra_Float4 packedTile)
{
gra_Float4 swiz;
#if GRA_BGRA == 0
swiz = packedTile;
#else
swiz = packedTile.zyxw;
#endif
swiz *= 255.0f;
float tileX = swiz.x + fmod(swiz.y, 16.0f) * 256.0f;
float tileY = floor(swiz.y / 16.0f) + swiz.z * 16.0f;
float level = fmod(swiz.w, 16.0f);
float tex = floor(swiz.w / 16.0f);
return gra_Float4(tileX, tileY, level, tex);
}
gra_Float3 GranitePrivate_TranslateCoord(in GraniteTilesetConstantBuffer tsCB, in gra_Float2 inputTexCoord, in gra_Float4 translationData, in int layer, out gra_Float2 numPagesOnLevel)
{
// The translation table contains uint32_t values so we have to get to the individual bits of the float data
uint data = GranitePrivate_FloatAsUint(translationData[layer]);
// Slice Index: 7 bits, Cache X: 10 bits, Cache Y: 10 bits, Tile Level: 4 bits
uint slice = (data >> 24u) & 0x7Fu;
uint cacheX = (data >> 14u) & 0x3FFu;
uint cacheY = (data >> 4u) & 0x3FFu;
uint revLevel = data & 0xFu;
gra_Float2 numTilesOnLevel;
numTilesOnLevel.x = GranitePrivate_Pow2(revLevel);
numTilesOnLevel.y = numTilesOnLevel.x * gra_NumTilesYScale;
gra_Float2 tileTexCoord = frac(inputTexCoord * numTilesOnLevel);
gra_Float2 tileTexCoordCache = tileTexCoord * gra_TileContentInTiles + gra_Float2(cacheX, cacheY);
gra_Float3 final = gra_Float3(tileTexCoordCache * gra_RcpCacheInTiles(layer) + gra_BorderPixelsRcpCache(layer), slice);
numPagesOnLevel = numTilesOnLevel * gra_TileContentInTiles * gra_RcpCacheInTiles(layer);
return final;
}
gra_Float4 GranitePrivate_DrawDebugTiles(in gra_Float4 sourceColor, in gra_Float2 textureCoord, in gra_Float2 numPagesOnLevel)
{
// Calculate the border values
gra_Float2 cacheOffs = frac(textureCoord * numPagesOnLevel);
float borderTemp = max(cacheOffs.x, 1.0-cacheOffs.x);
borderTemp = max(max(cacheOffs.y, 1.0-cacheOffs.y), borderTemp);
float border = smoothstep(0.98, 0.99, borderTemp);
// White
gra_Float4 borderColor = gra_Float4(1,1,1,1);
//Lerp it over the source color
return lerp(sourceColor, borderColor, border);
}
gra_Float4 GranitePrivate_MakeResolveOutput(in GraniteTilesetConstantBuffer tsCB, in gra_Float2 tileXY, in float level)
{
#if GRA_PACK_RESOLVE_OUTPUT
return GranitePrivate_PackTileId(tileXY, level, gra_TextureId);
#else
return gra_Float4(tileXY, level, gra_TextureId);
#endif
}
gra_Float4 GranitePrivate_ResolverPixel(in GraniteTilesetConstantBuffer tsCB, in gra_Float2 inputTexCoord, in float LOD)
{
float level = floor(LOD + 0.5f);
// Number of tiles on level zero
gra_Float2 level0NumTiles;
level0NumTiles.x = gra_Level0NumTilesX;
level0NumTiles.y = gra_Level0NumTilesX * gra_NumTilesYScale;
// Calculate xy of the tiles to load
gra_Float2 virtualTilesUv = floor(inputTexCoord * level0NumTiles * pow(0.5, level));
return GranitePrivate_MakeResolveOutput(tsCB, virtualTilesUv, level);
}
void GranitePrivate_CalculateCubemapCoordinates(in gra_Float3 inputTexCoord, in gra_Float3 dVx, in gra_Float3 dVy, in GraniteStreamingTextureCubeConstantBuffer transforms, out int faceIdx, out gra_Float2 texCoord, out gra_Float2 dX, out gra_Float2 dY)
{
gra_Float2 contTexCoord;
gra_Float3 derivX;
gra_Float3 derivY;
float majorAxis;
if (abs(inputTexCoord.z) >= abs(inputTexCoord.x) && abs(inputTexCoord.z) >= abs(inputTexCoord.y))
{
// Z major axis
if(inputTexCoord.z < 0.0)
{
faceIdx = 5;
texCoord.x = -inputTexCoord.x;
}
else
{
faceIdx = 4;
texCoord.x = inputTexCoord.x;
}
texCoord.y = -inputTexCoord.y;
majorAxis = inputTexCoord.z;
contTexCoord = gra_Float2(inputTexCoord.x, inputTexCoord.y);
derivX = gra_Float3(dVx.x, dVx.y, dVx.z);
derivY = gra_Float3(dVy.x, dVy.y, dVy.z);
}
else if (abs(inputTexCoord.y) >= abs(inputTexCoord.x))
{
// Y major axis
if(inputTexCoord.y < 0.0)
{
faceIdx = 3;
texCoord.y = -inputTexCoord.z;
}
else
{
faceIdx = 2;
texCoord.y = inputTexCoord.z;
}
texCoord.x = inputTexCoord.x;
majorAxis = inputTexCoord.y;
contTexCoord = gra_Float2(inputTexCoord.x, inputTexCoord.z);
derivX = gra_Float3(dVx.x, dVx.z, dVx.y);
derivY = gra_Float3(dVy.x, dVy.z, dVy.y);
}
else
{
// X major axis
if(inputTexCoord.x < 0.0)
{
faceIdx = 1;
texCoord.x = inputTexCoord.z;
}
else
{
faceIdx = 0;
texCoord.x = -inputTexCoord.z;
}
texCoord.y = -inputTexCoord.y;
majorAxis = inputTexCoord.x;
contTexCoord = gra_Float2(inputTexCoord.z, inputTexCoord.y);
derivX = gra_Float3(dVx.z, dVx.y, dVx.x);
derivY = gra_Float3(dVy.z, dVy.y, dVy.x);
}
texCoord = (texCoord + majorAxis) / (2.0 * abs(majorAxis));
#if GRA_HQ_CUBEMAPPING
dX = /*contTexCoord **/ ((contTexCoord + derivX.xy) / ( 2.0 * (majorAxis + derivX.z)) - (contTexCoord / (2.0 * majorAxis)));
dY = /*contTexCoord **/ ((contTexCoord + derivY.xy) / ( 2.0 * (majorAxis + derivY.z)) - (contTexCoord / (2.0 * majorAxis)));
#else
dX = ((/*contTexCoord **/ derivX.xy) / (2.0 * abs(majorAxis)));
dY = ((/*contTexCoord **/ derivY.xy) / (2.0 * abs(majorAxis)));
#endif
// Now scale the derivatives with the texture transform scale
dX *= transforms.data[faceIdx].data[0].zw;
dY *= transforms.data[faceIdx].data[0].zw;
}
// Auto-level
void GranitePrivate_CalculateCubemapCoordinates(in gra_Float3 inputTexCoord, in GraniteStreamingTextureCubeConstantBuffer transforms, out int faceIdx, out gra_Float2 texCoord, out gra_Float2 dX, out gra_Float2 dY)
{
gra_Float3 dVx = ddx(inputTexCoord);
gra_Float3 dVy = ddy(inputTexCoord);
GranitePrivate_CalculateCubemapCoordinates(inputTexCoord, dVx, dVy, transforms, faceIdx, texCoord, dX, dY);
}
gra_Float2 Granite_GetTextureDimensions(in GraniteStreamingTextureConstantBuffer grSTCB)
{
return gra_Float2(1.0 / gra_AssetWidthRcp, 1.0 / gra_AssetHeightRcp); //TODO(ddebaets) use HLSL rcp here
}

View File

@@ -0,0 +1,749 @@
#ifndef UNITY_IMAGE_BASED_LIGHTING_INCLUDED
#define UNITY_IMAGE_BASED_LIGHTING_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/BSDF.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Random.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Sampling.hlsl"
#ifndef UNITY_SPECCUBE_LOD_STEPS
// This is actuall the last mip index, we generate 7 mips of convolution
#define UNITY_SPECCUBE_LOD_STEPS 6
#endif
//-----------------------------------------------------------------------------
// Util image based lighting
//-----------------------------------------------------------------------------
// The *approximated* version of the non-linear remapping. It works by
// approximating the cone of the specular lobe, and then computing the MIP map level
// which (approximately) covers the footprint of the lobe with a single texel.
// Improves the perceptual roughness distribution.
real PerceptualRoughnessToMipmapLevel(real perceptualRoughness, uint mipMapCount)
{
perceptualRoughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness);
return perceptualRoughness * mipMapCount;
}
real PerceptualRoughnessToMipmapLevel(real perceptualRoughness)
{
return PerceptualRoughnessToMipmapLevel(perceptualRoughness, UNITY_SPECCUBE_LOD_STEPS);
}
// The *accurate* version of the non-linear remapping. It works by
// approximating the cone of the specular lobe, and then computing the MIP map level
// which (approximately) covers the footprint of the lobe with a single texel.
// Improves the perceptual roughness distribution and adds reflection (contact) hardening.
// TODO: optimize!
real PerceptualRoughnessToMipmapLevel(real perceptualRoughness, real NdotR)
{
real m = PerceptualRoughnessToRoughness(perceptualRoughness);
// Remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf
real n = (2.0 / max(REAL_EPS, m * m)) - 2.0;
// Remap from n_dot_h formulation to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html
n /= (4.0 * max(NdotR, REAL_EPS));
// remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)
perceptualRoughness = pow(2.0 / (n + 2.0), 0.25);
return perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;
}
// The inverse of the *approximated* version of perceptualRoughnessToMipmapLevel().
real MipmapLevelToPerceptualRoughness(real mipmapLevel)
{
real perceptualRoughness = saturate(mipmapLevel / UNITY_SPECCUBE_LOD_STEPS);
return saturate(1.7 / 1.4 - sqrt(2.89 / 1.96 - (2.8 / 1.96) * perceptualRoughness));
}
//-----------------------------------------------------------------------------
// Anisotropic image based lighting
//-----------------------------------------------------------------------------
// T is the fiber axis (hair strand direction, root to tip).
float3 ComputeViewFacingNormal(float3 V, float3 T)
{
return Orthonormalize(V, T);
}
// Fake anisotropy by distorting the normal (non-negative anisotropy values only).
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to N.
// Anisotropic ratio (0->no isotropic; 1->full anisotropy in tangent direction)
real3 GetAnisotropicModifiedNormal(real3 grainDir, real3 N, real3 V, real anisotropy)
{
real3 grainNormal = ComputeViewFacingNormal(V, grainDir);
return normalize(lerp(N, grainNormal, anisotropy));
}
// For GGX aniso and IBL we have done an empirical (eye balled) approximation compare to the reference.
// We use a single fetch, and we stretch the normal to use based on various criteria.
// result are far away from the reference but better than nothing
// Anisotropic ratio (0->no isotropic; 1->full anisotropy in tangent direction) - positive use bitangentWS - negative use tangentWS
// Note: returned iblPerceptualRoughness shouldn't be use for sampling FGD texture in a pre-integration
void GetGGXAnisotropicModifiedNormalAndRoughness(real3 bitangentWS, real3 tangentWS, real3 N, real3 V, real anisotropy, real perceptualRoughness, out real3 iblN, out real iblPerceptualRoughness)
{
// For positive anisotropy values: tangent = highlight stretch (anisotropy) direction, bitangent = grain (brush) direction.
float3 grainDirWS = (anisotropy >= 0.0) ? bitangentWS : tangentWS;
// Reduce stretching depends on the perceptual roughness
float stretch = abs(anisotropy) * saturate(1.5 * sqrt(perceptualRoughness));
// NOTE: If we follow the theory we should use the modified normal for the different calculation implying a normal (like NdotV)
// However modified normal is just a hack. The goal is just to stretch a cubemap, no accuracy here. Let's save performance instead.
iblN = GetAnisotropicModifiedNormal(grainDirWS, N, V, stretch);
iblPerceptualRoughness = perceptualRoughness * saturate(1.2 - abs(anisotropy));
}
// Ref: "Moving Frostbite to PBR", p. 69.
real3 GetSpecularDominantDir(real3 N, real3 R, real perceptualRoughness, real NdotV)
{
real p = perceptualRoughness;
real a = 1.0 - p * p;
real s = sqrt(a);
#ifdef USE_FB_DSD
// This is the original formulation.
real lerpFactor = (s + p * p) * a;
#else
// TODO: tweak this further to achieve a closer match to the reference.
real lerpFactor = (s + p * p) * saturate(a * a + lerp(0.0, a, NdotV * NdotV));
#endif
// The result is not normalized as we fetch in a cubemap
return lerp(N, R, lerpFactor);
}
// ----------------------------------------------------------------------------
// Importance sampling BSDF functions
// ----------------------------------------------------------------------------
void SampleGGXDir(real2 u,
real3 V,
real3x3 localToWorld,
real roughness,
out real3 L,
out real NdotL,
out real NdotH,
out real VdotH,
bool VeqN = false)
{
// GGX NDF sampling
real cosTheta = sqrt(SafeDiv(1.0 - u.x, 1.0 + (roughness * roughness - 1.0) * u.x));
real phi = TWO_PI * u.y;
real3 localH = SphericalToCartesian(phi, cosTheta);
NdotH = cosTheta;
real3 localV;
if (VeqN)
{
// localV == localN
localV = real3(0.0, 0.0, 1.0);
VdotH = NdotH;
}
else
{
localV = mul(V, transpose(localToWorld));
VdotH = saturate(dot(localV, localH));
}
// Compute { localL = reflect(-localV, localH) }
real3 localL = -localV + 2.0 * VdotH * localH;
NdotL = localL.z;
L = mul(localL, localToWorld);
}
// ref: http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf p26
void SampleAnisoGGXDir(real2 u,
real3 V,
real3 N,
real3 tangentX,
real3 tangentY,
real roughnessT,
real roughnessB,
out real3 H,
out real3 L)
{
// AnisoGGX NDF sampling
H = sqrt(u.x / (1.0 - u.x)) * (roughnessT * cos(TWO_PI * u.y) * tangentX + roughnessB * sin(TWO_PI * u.y) * tangentY) + N;
H = normalize(H);
// Convert sample from half angle to incident angle
L = 2.0 * saturate(dot(V, H)) * H - V;
}
// Adapted from: "Sampling the GGX Distribution of Visible Normals", by E. Heitz
// http://jcgt.org/published/0007/04/01/paper.pdf
void SampleAnisoGGXVisibleNormal(float2 u,
float3 V,
float3x3 localToWorld,
float roughnessX,
float roughnessY,
out float3 localV,
out float3 localH,
out float VdotH)
{
localV = mul(V, transpose(localToWorld));
// Construct an orthonormal basis around the stretched view direction
float3x3 viewToLocal;
viewToLocal[2] = normalize(float3(roughnessX * localV.x, roughnessY * localV.y, localV.z));
viewToLocal[0] = (viewToLocal[2].z < 0.9999) ? normalize(cross(float3(0, 0, 1), viewToLocal[2])) : float3(1, 0, 0);
viewToLocal[1] = cross(viewToLocal[2], viewToLocal[0]);
// Compute a sample point with polar coordinates (r, phi)
float r = sqrt(u.x);
float phi = 2.0 * PI * u.y;
float t1 = r * cos(phi);
float t2 = r * sin(phi);
float s = 0.5 * (1.0 + viewToLocal[2].z);
t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2;
// Reproject onto hemisphere
localH = t1 * viewToLocal[0] + t2 * viewToLocal[1] + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * viewToLocal[2];
// Transform the normal back to the ellipsoid configuration
localH = normalize(float3(roughnessX * localH.x, roughnessY * localH.y, max(0.0, localH.z)));
VdotH = saturate(dot(localV, localH));
}
// GGX vsible normal sampling, isotropic variant
void SampleGGXVisibleNormal(float2 u,
float3 V,
float3x3 localToWorld,
float roughness,
out float3 localV,
out float3 localH,
out float VdotH)
{
SampleAnisoGGXVisibleNormal(u, V, localToWorld, roughness, roughness, localV, localH, VdotH);
}
// weightOverPdf return the weight (without the diffuseAlbedo term) over pdf. diffuseAlbedo term must be apply by the caller.
void ImportanceSampleLambert(real2 u,
real3x3 localToWorld,
out real3 L,
out real NdotL,
out real weightOverPdf)
{
#if 0
real3 localL = SampleHemisphereCosine(u.x, u.y);
NdotL = localL.z;
L = mul(localL, localToWorld);
#else
real3 N = localToWorld[2];
L = SampleHemisphereCosine(u.x, u.y, N);
NdotL = saturate(dot(N, L));
#endif
// Importance sampling weight for each sample
// pdf = N.L / PI
// weight = fr * (N.L) with fr = diffuseAlbedo / PI
// weight over pdf is:
// weightOverPdf = (diffuseAlbedo / PI) * (N.L) / (N.L / PI)
// weightOverPdf = diffuseAlbedo
// diffuseAlbedo is apply outside the function
weightOverPdf = 1.0;
}
// weightOverPdf return the weight (without the Fresnel term) over pdf. Fresnel term must be apply by the caller.
void ImportanceSampleGGX(real2 u,
real3 V,
real3x3 localToWorld,
real roughness,
real NdotV,
out real3 L,
out real VdotH,
out real NdotL,
out real weightOverPdf)
{
real NdotH;
SampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH);
// Importance sampling weight for each sample
// pdf = D(H) * (N.H) / (4 * (L.H))
// weight = fr * (N.L) with fr = F(H) * G(V, L) * D(H) / (4 * (N.L) * (N.V))
// weight over pdf is:
// weightOverPdf = F(H) * G(V, L) * (L.H) / ((N.H) * (N.V))
// weightOverPdf = F(H) * 4 * (N.L) * V(V, L) * (L.H) / (N.H) with V(V, L) = G(V, L) / (4 * (N.L) * (N.V))
// Remind (L.H) == (V.H)
// F is apply outside the function
real Vis = V_SmithJointGGX(NdotL, NdotV, roughness);
weightOverPdf = 4.0 * Vis * NdotL * VdotH / NdotH;
}
// weightOverPdf return the weight (without the Fresnel term) over pdf. Fresnel term must be apply by the caller.
void ImportanceSampleAnisoGGX(real2 u,
real3 V,
real3x3 localToWorld,
real roughnessT,
real roughnessB,
real NdotV,
out real3 L,
out real VdotH,
out real NdotL,
out real weightOverPdf)
{
real3 tangentX = localToWorld[0];
real3 tangentY = localToWorld[1];
real3 N = localToWorld[2];
real3 H;
SampleAnisoGGXDir(u, V, N, tangentX, tangentY, roughnessT, roughnessB, H, L);
real NdotH = saturate(dot(N, H));
// Note: since L and V are symmetric around H, LdotH == VdotH
VdotH = saturate(dot(V, H));
NdotL = saturate(dot(N, L));
// Importance sampling weight for each sample
// pdf = D(H) * (N.H) / (4 * (L.H))
// weight = fr * (N.L) with fr = F(H) * G(V, L) * D(H) / (4 * (N.L) * (N.V))
// weight over pdf is:
// weightOverPdf = F(H) * G(V, L) * (L.H) / ((N.H) * (N.V))
// weightOverPdf = F(H) * 4 * (N.L) * V(V, L) * (L.H) / (N.H) with V(V, L) = G(V, L) / (4 * (N.L) * (N.V))
// Remind (L.H) == (V.H)
// F is apply outside the function
// For anisotropy we must not saturate these values
real TdotV = dot(tangentX, V);
real BdotV = dot(tangentY, V);
real TdotL = dot(tangentX, L);
real BdotL = dot(tangentY, L);
real Vis = V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB);
weightOverPdf = 4.0 * Vis * NdotL * VdotH / NdotH;
}
// ----------------------------------------------------------------------------
// Pre-integration
// ----------------------------------------------------------------------------
#if !defined SHADER_API_GLES
// Ref: Listing 18 in "Moving Frostbite to PBR" + https://knarkowicz.wordpress.com/2014/12/27/analytical-dfg-term-for-ibl/
real4 IntegrateGGXAndDisneyDiffuseFGD(real NdotV, real roughness, uint sampleCount = 4096)
{
// Note that our LUT covers the full [0, 1] range.
// Therefore, we don't really want to clamp NdotV here (else the lerp slope is wrong).
// However, if NdotV is 0, the integral is 0, so that's not what we want, either.
// Our runtime NdotV bias is quite large, so we use a smaller one here instead.
NdotV = max(NdotV, REAL_EPS);
real3 V = real3(sqrt(1 - NdotV * NdotV), 0, NdotV);
real4 acc = real4(0.0, 0.0, 0.0, 0.0);
real3x3 localToWorld = k_identity3x3;
for (uint i = 0; i < sampleCount; ++i)
{
real2 u = Hammersley2d(i, sampleCount);
real VdotH;
real NdotL;
real weightOverPdf;
real3 L; // Unused
ImportanceSampleGGX(u, V, localToWorld, roughness, NdotV,
L, VdotH, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
// Integral{BSDF * <N,L> dw} =
// Integral{(F0 + (1 - F0) * (1 - <V,H>)^5) * (BSDF / F) * <N,L> dw} =
// (1 - F0) * Integral{(1 - <V,H>)^5 * (BSDF / F) * <N,L> dw} + F0 * Integral{(BSDF / F) * <N,L> dw}=
// (1 - F0) * x + F0 * y = lerp(x, y, F0)
acc.x += weightOverPdf * pow(1 - VdotH, 5);
acc.y += weightOverPdf;
}
// for Disney we still use a Cosine importance sampling, true Disney importance sampling imply a look up table
ImportanceSampleLambert(u, localToWorld, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
real LdotV = dot(L, V);
real disneyDiffuse = DisneyDiffuseNoPI(NdotV, NdotL, LdotV, RoughnessToPerceptualRoughness(roughness));
acc.z += disneyDiffuse * weightOverPdf;
}
}
acc /= sampleCount;
// Remap from the [0.5, 1.5] to the [0, 1] range.
acc.z -= 0.5;
return acc;
}
#else
// Not supported due to lack of random library in GLES 2
#define IntegrateGGXAndDisneyDiffuseFGD ERROR_ON_UNSUPPORTED_FUNCTION(IntegrateGGXAndDisneyDiffuseFGD)
#endif
uint GetIBLRuntimeFilterSampleCount(uint mipLevel)
{
uint sampleCount = 0;
switch (mipLevel)
{
case 1: sampleCount = 21; break;
case 2: sampleCount = 34; break;
#if defined(SHADER_API_MOBILE) || defined(SHADER_API_SWITCH)
case 3: sampleCount = 34; break;
case 4: sampleCount = 34; break;
case 5: sampleCount = 34; break;
case 6: sampleCount = 34; break; // UNITY_SPECCUBE_LOD_STEPS
#else
case 3: sampleCount = 55; break;
case 4: sampleCount = 89; break;
case 5: sampleCount = 89; break;
case 6: sampleCount = 89; break; // UNITY_SPECCUBE_LOD_STEPS
#endif
}
return sampleCount;
}
// Ref: Listing 19 in "Moving Frostbite to PBR"
real4 IntegrateLD(TEXTURECUBE_PARAM(tex, sampl),
TEXTURE2D(ggxIblSamples),
real3 V,
real3 N,
real roughness,
real index, // Current MIP level minus one
real invOmegaP,
uint sampleCount, // Must be a Fibonacci number
bool prefilter,
bool usePrecomputedSamples)
{
real3x3 localToWorld = GetLocalFrame(N);
#ifndef USE_KARIS_APPROXIMATION
real NdotV = 1; // N == V
real partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
#endif
real3 lightInt = real3(0.0, 0.0, 0.0);
real cbsdfInt = 0.0;
for (uint i = 0; i < sampleCount; ++i)
{
real3 L;
real NdotL, NdotH, LdotH;
if (usePrecomputedSamples)
{
// Performance warning: using a texture LUT will generate a vector load,
// which increases both the VGPR pressure and the workload of the
// texture unit. A better solution here is to load from a Constant, Raw
// or Structured buffer, or perhaps even declare all the constants in an
// HLSL header to allow the compiler to inline everything.
real3 localL = LOAD_TEXTURE2D(ggxIblSamples, uint2(i, index)).xyz;
L = mul(localL, localToWorld);
NdotL = localL.z;
LdotH = sqrt(0.5 + 0.5 * NdotL);
}
else
{
real2 u = Fibonacci2d(i, sampleCount);
// Note: if (N == V), all of the microsurface normals are visible.
SampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, LdotH, true);
if (NdotL <= 0) continue; // Note that some samples will have 0 contribution
}
real mipLevel;
if (!prefilter) // BRDF importance sampling
{
mipLevel = 0;
}
else // Prefiltered BRDF importance sampling
{
// Use lower MIP-map levels for fetching samples with low probabilities
// in order to reduce the variance.
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
//
// - OmegaS: Solid angle associated with the sample
// - OmegaP: Solid angle associated with the texel of the cubemap
real omegaS;
if (usePrecomputedSamples)
{
omegaS = LOAD_TEXTURE2D(ggxIblSamples, uint2(i, index)).w;
}
else
{
// real PDF = D * NdotH * Jacobian, where Jacobian = 1 / (4 * LdotH).
// Since (N == V), NdotH == LdotH.
real pdf = 0.25 * D_GGX(NdotH, roughness);
// TODO: improve the accuracy of the sample's solid angle fit for GGX.
omegaS = rcp(sampleCount) * rcp(pdf);
}
// 'invOmegaP' is precomputed on CPU and provided as a parameter to the function.
// real omegaP = FOUR_PI / (6.0 * cubemapWidth * cubemapWidth);
const real mipBias = roughness;
mipLevel = 0.5 * log2(omegaS * invOmegaP) + mipBias;
}
// TODO: use a Gaussian-like filter to generate the MIP pyramid.
real3 val = SAMPLE_TEXTURECUBE_LOD(tex, sampl, L, mipLevel).rgb;
// The goal of this function is to use Monte-Carlo integration to find
// X = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// Note: Integral{CBSDF(L, N, V) dL} is given by the FDG texture.
// CBSDF = F * D * G * NdotL / (4 * NdotL * NdotV) = F * D * G / (4 * NdotV).
// PDF = D * NdotH / (4 * LdotH).
// Weight = CBSDF / PDF = F * G * LdotH / (NdotV * NdotH).
// Since we perform filtering with the assumption that (V == N),
// (LdotH == NdotH) && (NdotV == 1) && (Weight == F * G).
// Therefore, after the Monte Carlo expansion of the integrals,
// X = Sum(Radiance(L) * Weight) / Sum(Weight) = Sum(Radiance(L) * F * G) / Sum(F * G).
#ifndef USE_KARIS_APPROXIMATION
// The choice of the Fresnel factor does not appear to affect the result.
real F = 1; // F_Schlick(F0, LdotH);
real G = V_SmithJointGGX(NdotL, NdotV, roughness, partLambdaV) * NdotL * NdotV; // 4 cancels out
lightInt += F * G * val;
cbsdfInt += F * G;
#else
// Use the approximation from "Real Shading in Unreal Engine 4": Weight ~ NdotL.
lightInt += NdotL * val;
cbsdfInt += NdotL;
#endif
}
return real4(lightInt / cbsdfInt, 1.0);
}
real4 IntegrateLDCharlie(TEXTURECUBE_PARAM(tex, sampl),
real3 V,
real3 N,
real roughness,
uint sampleCount,
real invOmegaP,
bool prefilter)
{
// Local frame for the local to world sample transformation
real3x3 localToWorld = GetLocalFrame(N);
float NdotV = 1;
// Cumulative values
real3 lightInt = real3(0.0, 0.0, 0.0);
real cbsdfInt = 0.0;
for (uint i = 0; i < sampleCount; ++i)
{
// Generate a new random number
real2 u = Hammersley2d(i, sampleCount);
// Generate the matching direction with a cosine importance sampling
float3 localL = SampleHemisphereCosine(u.x, u.y);
// Convert it to world space
real3 L = mul(localL, localToWorld);
float NdotL = saturate(dot(N, L));
// Are we in the hemisphere?
if (NdotL <= 0) continue; // Note that some samples will have 0 contribution
// The goal of this function is to use Monte-Carlo integration to find
// X = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// Note: Integral{CBSDF(L, N, V) dL} is given by the FDG texture.
// CBSDF = F * D * V * NdotL.
// PDF = 1.0 / NdotL
// Weight = CBSDF / PDF = F * D * V
// Since we perform filtering with the assumption that (V == N),
// (LdotH == NdotH) && (NdotV == 1) && (Weight == F * D * V)
// Therefore, after the Monte Carlo expansion of the integrals,
// X = Sum(Radiance(L) * Weight) / Sum(Weight) = Sum(Radiance(L) * F * D * V) / Sum(F * D * V).
// We are in the supposition that N == V
float LdotV, NdotH, LdotH, invLenLV;
GetBSDFAngle(V, L, NdotL, NdotV, LdotV, NdotH, LdotH, invLenLV);
// BRDF data
real F = 1;
real D = D_Charlie(NdotH, roughness);
real Vis = V_Charlie(NdotL, NdotV, roughness);
real mipLevel = 0;
if (prefilter) // Prefiltered BRDF importance sampling
{
// Use lower MIP-map levels for fetching samples with low probabilities
// in order to reduce the variance.
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
//
// - OmegaS: Solid angle associated with the sample
// - OmegaP: Solid angle associated with the texel of the cubemap
real omegaS;
// real PDF = 1.0f / NdotL
// Since (N == V), NdotH == LdotH.
real pdf = 1.0 / NdotL;
// TODO: improve the accuracy of the sample's solid angle fit for GGX.
omegaS = rcp(sampleCount) * rcp(pdf);
// 'invOmegaP' is precomputed on CPU and provided as a parameter to the function.
// real omegaP = FOUR_PI / (6.0 * cubemapWidth * cubemapWidth);
const real mipBias = roughness;
mipLevel = 0.5 * log2(omegaS * invOmegaP) + mipBias;
}
// TODO: use a Gaussian-like filter to generate the MIP pyramid.
real3 val = SAMPLE_TEXTURECUBE_LOD(tex, sampl, L, mipLevel).rgb;
// Use the approximation from "Real Shading in Unreal Engine 4": Weight ~ NdotL.
lightInt += val * F * D * Vis;
cbsdfInt += F * D * Vis;
}
return real4(lightInt / cbsdfInt, 1.0);
}
// Searches the row 'j' containing 'n' elements of 'haystack' and
// returns the index of the first element greater or equal to 'needle'.
uint BinarySearchRow(uint j, real needle, TEXTURE2D(haystack), uint n)
{
uint i = n - 1;
real v = LOAD_TEXTURE2D(haystack, uint2(i, j)).r;
if (needle < v)
{
i = 0;
for (uint b = 1 << firstbithigh(n - 1); b != 0; b >>= 1)
{
uint p = i | b;
v = LOAD_TEXTURE2D(haystack, uint2(p, j)).r;
if (v <= needle) { i = p; } // Move to the right.
}
}
return i;
}
#if !defined SHADER_API_GLES
real4 IntegrateLD_MIS(TEXTURECUBE_PARAM(envMap, sampler_envMap),
TEXTURE2D(marginalRowDensities),
TEXTURE2D(conditionalDensities),
real3 V,
real3 N,
real roughness,
real invOmegaP,
uint width,
uint height,
uint sampleCount,
bool prefilter)
{
real3x3 localToWorld = GetLocalFrame(N);
real3 lightInt = real3(0.0, 0.0, 0.0);
real cbsdfInt = 0.0;
/*
// Dedicate 50% of samples to light sampling at 1.0 roughness.
// Only perform BSDF sampling when roughness is below 0.5.
const int lightSampleCount = lerp(0, sampleCount / 2, saturate(2.0 * roughness - 1.0));
const int bsdfSampleCount = sampleCount - lightSampleCount;
*/
// The value of the integral of intensity values of the environment map (as a 2D step function).
real envMapInt2dStep = LOAD_TEXTURE2D(marginalRowDensities, uint2(height, 0)).r;
// Since we are using equiareal mapping, we need to divide by the area of the sphere.
real envMapIntSphere = envMapInt2dStep * INV_FOUR_PI;
// Perform light importance sampling.
for (uint i = 0; i < sampleCount; i++)
{
real2 s = Hammersley2d(i, sampleCount);
// Sample a row from the marginal distribution.
uint y = BinarySearchRow(0, s.x, marginalRowDensities, height - 1);
// Sample a column from the conditional distribution.
uint x = BinarySearchRow(y, s.y, conditionalDensities, width - 1);
// Compute the coordinates of the sample.
// Note: we take the sample in between two texels, and also apply the half-texel offset.
// We could compute fractional coordinates at the cost of 4 extra texel samples.
real u = saturate((real)x / width + 1.0 / width);
real v = saturate((real)y / height + 1.0 / height);
real3 L = ConvertEquiarealToCubemap(u, v);
real NdotL = saturate(dot(N, L));
if (NdotL > 0.0)
{
real3 val = SAMPLE_TEXTURECUBE_LOD(envMap, sampler_envMap, L, 0).rgb;
real pdf = (val.r + val.g + val.b) / envMapIntSphere;
if (pdf > 0.0)
{
// (N == V) && (acos(VdotL) == 2 * acos(NdotH)).
real NdotH = sqrt(NdotL * 0.5 + 0.5);
// *********************************************************************************
// Our goal is to use Monte-Carlo integration with importance sampling to evaluate
// X(V) = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// CBSDF = F * D * G * NdotL / (4 * NdotL * NdotV) = F * D * G / (4 * NdotV).
// Weight = CBSDF / PDF.
// We use two approximations of Brian Karis from "Real Shading in Unreal Engine 4":
// (F * G ~ NdotL) && (NdotV == 1).
// Weight = D * NdotL / (4 * PDF).
// *********************************************************************************
real weight = D_GGX(NdotH, roughness) * NdotL / (4.0 * pdf);
lightInt += weight * val;
cbsdfInt += weight;
}
}
}
// Prevent NaNs arising from the division of 0 by 0.
cbsdfInt = max(cbsdfInt, REAL_EPS);
return real4(lightInt / cbsdfInt, 1.0);
}
#else
// Not supported due to lack of random library in GLES 2
#define IntegrateLD_MIS ERROR_ON_UNSUPPORTED_FUNCTION(IntegrateLD_MIS)
#endif
// Little helper to share code between sphere and box reflection probe.
// This function will fade the mask of a reflection volume based on normal orientation compare to direction define by the center of the reflection volume.
float InfluenceFadeNormalWeight(float3 normal, float3 centerToPos)
{
// Start weight from 0.6f (1 fully transparent) to 0.2f (fully opaque).
return saturate((-1.0f / 0.4f) * dot(normal, centerToPos) + (0.6f / 0.4f));
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_IMAGE_BASED_LIGHTING_INCLUDED

View File

@@ -0,0 +1,241 @@
#ifndef UNITY_MACROS_INCLUDED
#define UNITY_MACROS_INCLUDED
// Some shader compiler don't support to do multiple ## for concatenation inside the same macro, it require an indirection.
// This is the purpose of this macro
#define MERGE_NAME(X, Y) X##Y
#define CALL_MERGE_NAME(X, Y) MERGE_NAME(X, Y)
// These define are use to abstract the way we sample into a cubemap array.
// Some platform don't support cubemap array so we fallback on 2D latlong
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURE2D_ARRAY
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURE2D_ARRAY_PARAM
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURE2D_ARRAY_ARGS
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, DirectionToLatLongCoordinate(coord3), index, lod)
#else
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURECUBE_ARRAY
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURECUBE_ARRAY_PARAM
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURECUBE_ARRAY_ARGS
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#endif
#define PI 3.14159265358979323846
#define TWO_PI 6.28318530717958647693
#define FOUR_PI 12.5663706143591729538
#define INV_PI 0.31830988618379067154
#define INV_TWO_PI 0.15915494309189533577
#define INV_FOUR_PI 0.07957747154594766788
#define HALF_PI 1.57079632679489661923
#define INV_HALF_PI 0.63661977236758134308
#define LOG2_E 1.44269504088896340736
#define INV_SQRT2 0.70710678118654752440
#define PI_DIV_FOUR 0.78539816339744830961
#define MILLIMETERS_PER_METER 1000
#define METERS_PER_MILLIMETER rcp(MILLIMETERS_PER_METER)
#define CENTIMETERS_PER_METER 100
#define METERS_PER_CENTIMETER rcp(CENTIMETERS_PER_METER)
#define FLT_INF asfloat(0x7F800000)
#define FLT_EPS 5.960464478e-8 // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
#define FLT_MIN 1.175494351e-38 // Minimum normalized positive floating-point number
#define FLT_MAX 3.402823466e+38 // Maximum representable floating-point number
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
#define HALF_MIN 6.103515625e-5 // 2^-14, the same value for 10, 11 and 16-bit: https://www.khronos.org/opengl/wiki/Small_Float_Formats
#define HALF_MIN_SQRT 0.0078125 // 2^-7 == sqrt(HALF_MIN), useful for ensuring HALF_MIN after x^2
#define HALF_MAX 65504.0
#define UINT_MAX 0xFFFFFFFFu
#define INT_MAX 0x7FFFFFFF
#ifdef SHADER_API_GLES
#define GENERATE_INT_FLOAT_1_ARG(FunctionName, Parameter1, FunctionBody) \
float FunctionName(float Parameter1) { FunctionBody; } \
int FunctionName(int Parameter1) { FunctionBody; }
#else
#define GENERATE_INT_FLOAT_1_ARG(FunctionName, Parameter1, FunctionBody) \
float FunctionName(float Parameter1) { FunctionBody; } \
uint FunctionName(uint Parameter1) { FunctionBody; } \
int FunctionName(int Parameter1) { FunctionBody; }
#endif
#define TEMPLATE_1_FLT(FunctionName, Parameter1, FunctionBody) \
float FunctionName(float Parameter1) { FunctionBody; } \
float2 FunctionName(float2 Parameter1) { FunctionBody; } \
float3 FunctionName(float3 Parameter1) { FunctionBody; } \
float4 FunctionName(float4 Parameter1) { FunctionBody; }
#define TEMPLATE_1_HALF(FunctionName, Parameter1, FunctionBody) \
half FunctionName(half Parameter1) { FunctionBody; } \
half2 FunctionName(half2 Parameter1) { FunctionBody; } \
half3 FunctionName(half3 Parameter1) { FunctionBody; } \
half4 FunctionName(half4 Parameter1) { FunctionBody; } \
float FunctionName(float Parameter1) { FunctionBody; } \
float2 FunctionName(float2 Parameter1) { FunctionBody; } \
float3 FunctionName(float3 Parameter1) { FunctionBody; } \
float4 FunctionName(float4 Parameter1) { FunctionBody; }
#ifdef SHADER_API_GLES
#define TEMPLATE_1_INT(FunctionName, Parameter1, FunctionBody) \
int FunctionName(int Parameter1) { FunctionBody; } \
int2 FunctionName(int2 Parameter1) { FunctionBody; } \
int3 FunctionName(int3 Parameter1) { FunctionBody; } \
int4 FunctionName(int4 Parameter1) { FunctionBody; }
#else
#define TEMPLATE_1_INT(FunctionName, Parameter1, FunctionBody) \
int FunctionName(int Parameter1) { FunctionBody; } \
int2 FunctionName(int2 Parameter1) { FunctionBody; } \
int3 FunctionName(int3 Parameter1) { FunctionBody; } \
int4 FunctionName(int4 Parameter1) { FunctionBody; } \
uint FunctionName(uint Parameter1) { FunctionBody; } \
uint2 FunctionName(uint2 Parameter1) { FunctionBody; } \
uint3 FunctionName(uint3 Parameter1) { FunctionBody; } \
uint4 FunctionName(uint4 Parameter1) { FunctionBody; }
#endif
#define TEMPLATE_2_FLT(FunctionName, Parameter1, Parameter2, FunctionBody) \
float FunctionName(float Parameter1, float Parameter2) { FunctionBody; } \
float2 FunctionName(float2 Parameter1, float2 Parameter2) { FunctionBody; } \
float3 FunctionName(float3 Parameter1, float3 Parameter2) { FunctionBody; } \
float4 FunctionName(float4 Parameter1, float4 Parameter2) { FunctionBody; }
#define TEMPLATE_2_HALF(FunctionName, Parameter1, Parameter2, FunctionBody) \
half FunctionName(half Parameter1, half Parameter2) { FunctionBody; } \
half2 FunctionName(half2 Parameter1, half2 Parameter2) { FunctionBody; } \
half3 FunctionName(half3 Parameter1, half3 Parameter2) { FunctionBody; } \
half4 FunctionName(half4 Parameter1, half4 Parameter2) { FunctionBody; } \
float FunctionName(float Parameter1, float Parameter2) { FunctionBody; } \
float2 FunctionName(float2 Parameter1, float2 Parameter2) { FunctionBody; } \
float3 FunctionName(float3 Parameter1, float3 Parameter2) { FunctionBody; } \
float4 FunctionName(float4 Parameter1, float4 Parameter2) { FunctionBody; }
#ifdef SHADER_API_GLES
#define TEMPLATE_2_INT(FunctionName, Parameter1, Parameter2, FunctionBody) \
int FunctionName(int Parameter1, int Parameter2) { FunctionBody; } \
int2 FunctionName(int2 Parameter1, int2 Parameter2) { FunctionBody; } \
int3 FunctionName(int3 Parameter1, int3 Parameter2) { FunctionBody; } \
int4 FunctionName(int4 Parameter1, int4 Parameter2) { FunctionBody; }
#else
#define TEMPLATE_2_INT(FunctionName, Parameter1, Parameter2, FunctionBody) \
int FunctionName(int Parameter1, int Parameter2) { FunctionBody; } \
int2 FunctionName(int2 Parameter1, int2 Parameter2) { FunctionBody; } \
int3 FunctionName(int3 Parameter1, int3 Parameter2) { FunctionBody; } \
int4 FunctionName(int4 Parameter1, int4 Parameter2) { FunctionBody; } \
uint FunctionName(uint Parameter1, uint Parameter2) { FunctionBody; } \
uint2 FunctionName(uint2 Parameter1, uint2 Parameter2) { FunctionBody; } \
uint3 FunctionName(uint3 Parameter1, uint3 Parameter2) { FunctionBody; } \
uint4 FunctionName(uint4 Parameter1, uint4 Parameter2) { FunctionBody; }
#endif
#define TEMPLATE_3_FLT(FunctionName, Parameter1, Parameter2, Parameter3, FunctionBody) \
float FunctionName(float Parameter1, float Parameter2, float Parameter3) { FunctionBody; } \
float2 FunctionName(float2 Parameter1, float2 Parameter2, float2 Parameter3) { FunctionBody; } \
float3 FunctionName(float3 Parameter1, float3 Parameter2, float3 Parameter3) { FunctionBody; } \
float4 FunctionName(float4 Parameter1, float4 Parameter2, float4 Parameter3) { FunctionBody; }
#define TEMPLATE_3_HALF(FunctionName, Parameter1, Parameter2, Parameter3, FunctionBody) \
half FunctionName(half Parameter1, half Parameter2, half Parameter3) { FunctionBody; } \
half2 FunctionName(half2 Parameter1, half2 Parameter2, half2 Parameter3) { FunctionBody; } \
half3 FunctionName(half3 Parameter1, half3 Parameter2, half3 Parameter3) { FunctionBody; } \
half4 FunctionName(half4 Parameter1, half4 Parameter2, half4 Parameter3) { FunctionBody; } \
float FunctionName(float Parameter1, float Parameter2, float Parameter3) { FunctionBody; } \
float2 FunctionName(float2 Parameter1, float2 Parameter2, float2 Parameter3) { FunctionBody; } \
float3 FunctionName(float3 Parameter1, float3 Parameter2, float3 Parameter3) { FunctionBody; } \
float4 FunctionName(float4 Parameter1, float4 Parameter2, float4 Parameter3) { FunctionBody; }
#ifdef SHADER_API_GLES
#define TEMPLATE_3_INT(FunctionName, Parameter1, Parameter2, Parameter3, FunctionBody) \
int FunctionName(int Parameter1, int Parameter2, int Parameter3) { FunctionBody; } \
int2 FunctionName(int2 Parameter1, int2 Parameter2, int2 Parameter3) { FunctionBody; } \
int3 FunctionName(int3 Parameter1, int3 Parameter2, int3 Parameter3) { FunctionBody; } \
int4 FunctionName(int4 Parameter1, int4 Parameter2, int4 Parameter3) { FunctionBody; }
#else
#define TEMPLATE_3_INT(FunctionName, Parameter1, Parameter2, Parameter3, FunctionBody) \
int FunctionName(int Parameter1, int Parameter2, int Parameter3) { FunctionBody; } \
int2 FunctionName(int2 Parameter1, int2 Parameter2, int2 Parameter3) { FunctionBody; } \
int3 FunctionName(int3 Parameter1, int3 Parameter2, int3 Parameter3) { FunctionBody; } \
int4 FunctionName(int4 Parameter1, int4 Parameter2, int4 Parameter3) { FunctionBody; } \
uint FunctionName(uint Parameter1, uint Parameter2, uint Parameter3) { FunctionBody; } \
uint2 FunctionName(uint2 Parameter1, uint2 Parameter2, uint2 Parameter3) { FunctionBody; } \
uint3 FunctionName(uint3 Parameter1, uint3 Parameter2, uint3 Parameter3) { FunctionBody; } \
uint4 FunctionName(uint4 Parameter1, uint4 Parameter2, uint4 Parameter3) { FunctionBody; }
#endif
#ifdef SHADER_API_GLES
#define TEMPLATE_SWAP(FunctionName) \
void FunctionName(inout real a, inout real b) { real t = a; a = b; b = t; } \
void FunctionName(inout real2 a, inout real2 b) { real2 t = a; a = b; b = t; } \
void FunctionName(inout real3 a, inout real3 b) { real3 t = a; a = b; b = t; } \
void FunctionName(inout real4 a, inout real4 b) { real4 t = a; a = b; b = t; } \
void FunctionName(inout int a, inout int b) { int t = a; a = b; b = t; } \
void FunctionName(inout int2 a, inout int2 b) { int2 t = a; a = b; b = t; } \
void FunctionName(inout int3 a, inout int3 b) { int3 t = a; a = b; b = t; } \
void FunctionName(inout int4 a, inout int4 b) { int4 t = a; a = b; b = t; } \
void FunctionName(inout bool a, inout bool b) { bool t = a; a = b; b = t; } \
void FunctionName(inout bool2 a, inout bool2 b) { bool2 t = a; a = b; b = t; } \
void FunctionName(inout bool3 a, inout bool3 b) { bool3 t = a; a = b; b = t; } \
void FunctionName(inout bool4 a, inout bool4 b) { bool4 t = a; a = b; b = t; }
#else
#if REAL_IS_HALF
#define TEMPLATE_SWAP(FunctionName) \
void FunctionName(inout real a, inout real b) { real t = a; a = b; b = t; } \
void FunctionName(inout real2 a, inout real2 b) { real2 t = a; a = b; b = t; } \
void FunctionName(inout real3 a, inout real3 b) { real3 t = a; a = b; b = t; } \
void FunctionName(inout real4 a, inout real4 b) { real4 t = a; a = b; b = t; } \
void FunctionName(inout float a, inout float b) { float t = a; a = b; b = t; } \
void FunctionName(inout float2 a, inout float2 b) { float2 t = a; a = b; b = t; } \
void FunctionName(inout float3 a, inout float3 b) { float3 t = a; a = b; b = t; } \
void FunctionName(inout float4 a, inout float4 b) { float4 t = a; a = b; b = t; } \
void FunctionName(inout int a, inout int b) { int t = a; a = b; b = t; } \
void FunctionName(inout int2 a, inout int2 b) { int2 t = a; a = b; b = t; } \
void FunctionName(inout int3 a, inout int3 b) { int3 t = a; a = b; b = t; } \
void FunctionName(inout int4 a, inout int4 b) { int4 t = a; a = b; b = t; } \
void FunctionName(inout uint a, inout uint b) { uint t = a; a = b; b = t; } \
void FunctionName(inout uint2 a, inout uint2 b) { uint2 t = a; a = b; b = t; } \
void FunctionName(inout uint3 a, inout uint3 b) { uint3 t = a; a = b; b = t; } \
void FunctionName(inout uint4 a, inout uint4 b) { uint4 t = a; a = b; b = t; } \
void FunctionName(inout bool a, inout bool b) { bool t = a; a = b; b = t; } \
void FunctionName(inout bool2 a, inout bool2 b) { bool2 t = a; a = b; b = t; } \
void FunctionName(inout bool3 a, inout bool3 b) { bool3 t = a; a = b; b = t; } \
void FunctionName(inout bool4 a, inout bool4 b) { bool4 t = a; a = b; b = t; }
#else
#define TEMPLATE_SWAP(FunctionName) \
void FunctionName(inout real a, inout real b) { real t = a; a = b; b = t; } \
void FunctionName(inout real2 a, inout real2 b) { real2 t = a; a = b; b = t; } \
void FunctionName(inout real3 a, inout real3 b) { real3 t = a; a = b; b = t; } \
void FunctionName(inout real4 a, inout real4 b) { real4 t = a; a = b; b = t; } \
void FunctionName(inout int a, inout int b) { int t = a; a = b; b = t; } \
void FunctionName(inout int2 a, inout int2 b) { int2 t = a; a = b; b = t; } \
void FunctionName(inout int3 a, inout int3 b) { int3 t = a; a = b; b = t; } \
void FunctionName(inout int4 a, inout int4 b) { int4 t = a; a = b; b = t; } \
void FunctionName(inout uint a, inout uint b) { uint t = a; a = b; b = t; } \
void FunctionName(inout uint2 a, inout uint2 b) { uint2 t = a; a = b; b = t; } \
void FunctionName(inout uint3 a, inout uint3 b) { uint3 t = a; a = b; b = t; } \
void FunctionName(inout uint4 a, inout uint4 b) { uint4 t = a; a = b; b = t; } \
void FunctionName(inout bool a, inout bool b) { bool t = a; a = b; b = t; } \
void FunctionName(inout bool2 a, inout bool2 b) { bool2 t = a; a = b; b = t; } \
void FunctionName(inout bool3 a, inout bool3 b) { bool3 t = a; a = b; b = t; } \
void FunctionName(inout bool4 a, inout bool4 b) { bool4 t = a; a = b; b = t; }
#endif
#endif
// MACRO from Legacy Untiy
// Transforms 2D UV by scale/bias property
#define TRANSFORM_TEX(tex, name) ((tex.xy) * name##_ST.xy + name##_ST.zw)
#define GET_TEXELSIZE_NAME(name) (name##_TexelSize)
#if UNITY_REVERSED_Z
# define COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, zDevice) (shadowMapDepth > zDevice)
# define COMPARE_DEVICE_DEPTH_CLOSEREQUAL(shadowMapDepth, zDevice) (shadowMapDepth >= zDevice)
#else
# define COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, zDevice) (shadowMapDepth < zDevice)
# define COMPARE_DEVICE_DEPTH_CLOSEREQUAL(shadowMapDepth, zDevice) (shadowMapDepth <= zDevice)
#endif
#endif // UNITY_MACROS_INCLUDED

View File

@@ -0,0 +1,93 @@
// this produces an orthonormal basis of the tangent and bitangent WITHOUT vertex level tangent/bitangent for any UV including procedurally generated
// method released with the demo for publication of "bump mapping unparametrized surfaces on the GPU"
// http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
void SurfaceGradientGenBasisTB(float3 nrmVertexNormal, float3 sigmaX, float3 sigmaY, float flipSign, float2 texST, out float3 vT, out float3 vB)
{
float2 dSTdx = ddx_fine(texST), dSTdy = ddy_fine(texST);
float det = dot(dSTdx, float2(dSTdy.y, -dSTdy.x));
float sign_det = det < 0 ? -1 : 1;
// invC0 represents (dXds, dYds); but we don't divide by determinant (scale by sign instead)
float2 invC0 = sign_det * float2(dSTdy.y, -dSTdx.y);
vT = sigmaX * invC0.x + sigmaY * invC0.y;
if (abs(det) > 0.0)
vT = normalize(vT);
vB = (sign_det * flipSign) * cross(nrmVertexNormal, vT);
}
// surface gradient from an on the fly TBN (deriv obtained using tspaceNormalToDerivative()) or from conventional vertex level TBN (mikktspace compliant and deriv obtained using tspaceNormalToDerivative())
real3 SurfaceGradientFromTBN(real2 deriv, real3 vT, real3 vB)
{
return deriv.x * vT + deriv.y * vB;
}
// surface gradient from an already generated "normal" such as from an object or world space normal map
// CAUTION: nrmVertexNormal and v must be in the same space. i.e world or object
// this allows us to mix the contribution together with a series of other contributions including tangent space normals
// v does not need to be unit length as long as it establishes the direction.
real3 SurfaceGradientFromPerturbedNormal(real3 nrmVertexNormal, real3 v)
{
real3 n = nrmVertexNormal;
real s = 1.0 / max(REAL_EPS, abs(dot(n, v)));
return s * (dot(n, v) * n - v);
}
// used to produce a surface gradient from the gradient of a volume bump function such as a volume of perlin noise.
// equation 2. in "bump mapping unparametrized surfaces on the GPU".
// Observe the difference in figure 2. between using the gradient vs. the surface gradient to do bump mapping (the original method is proved wrong in the paper!).
real3 SurfaceGradientFromVolumeGradient(real3 nrmVertexNormal, real3 grad)
{
return grad - dot(nrmVertexNormal, grad) * nrmVertexNormal;
}
// triplanar projection considered special case of volume bump map
// described here: http://mmikkelsen3d.blogspot.com/2013/10/volume-height-maps-and-triplanar-bump.html
// derivs obtained using tspaceNormalToDerivative() and weights using computeTriplanarWeights().
real3 SurfaceGradientFromTriplanarProjection(real3 nrmVertexNormal, real3 triplanarWeights, real2 deriv_xplane, real2 deriv_yplane, real2 deriv_zplane)
{
const real w0 = triplanarWeights.x, w1 = triplanarWeights.y, w2 = triplanarWeights.z;
// assume deriv_xplane, deriv_yplane and deriv_zplane sampled using (z,y), (z,x) and (x,y) respectively.
// positive scales of the look-up coordinate will work as well but for negative scales the derivative components will need to be negated accordingly.
real3 volumeGrad = real3(w2 * deriv_zplane.x + w1 * deriv_yplane.y, w2 * deriv_zplane.y + w0 * deriv_xplane.y, w0 * deriv_xplane.x + w1 * deriv_yplane.x);
return SurfaceGradientFromVolumeGradient(nrmVertexNormal, volumeGrad);
}
real3 SurfaceGradientResolveNormal(real3 nrmVertexNormal, real3 surfGrad)
{
return SafeNormalize(nrmVertexNormal - surfGrad);
}
real2 ConvertTangentSpaceNormalToHeightMapGradient(real2 normalXY, real rcpNormalZ, real scale)
{
// scale * (-normal.xy / normal.z)
return normalXY * (-rcpNormalZ * scale);
}
// Converts tangent space normal to slopes (height map gradient).
real2 UnpackDerivativeNormalRGB(real4 packedNormal, real scale = 1.0)
{
real3 vT = packedNormal.rgb * 2.0 - 1.0; // Unsigned to signed
real rcpZ = rcp(max(vT.z, REAL_EPS)); // Clamp to avoid INF
return ConvertTangentSpaceNormalToHeightMapGradient(vT.xy, rcpZ, scale);
}
// Converts tangent space normal to slopes (height map gradient).
real2 UnpackDerivativeNormalAG(real4 packedNormal, real scale = 1.0)
{
real2 vT = packedNormal.ag * 2.0 - 1.0; // Unsigned to signed
real rcpZ = rsqrt(max(1 - Sq(vT.x) - Sq(vT.y), Sq(REAL_EPS))); // Clamp to avoid INF
return ConvertTangentSpaceNormalToHeightMapGradient(vT.xy, rcpZ, scale);
}
// Unpack normal as DXT5nm (1, y, 0, x) or BC5 (x, y, 0, 1)
real2 UnpackDerivativeNormalRGorAG(real4 packedNormal, real scale = 1.0)
{
// Convert to (?, y, 0, x)
packedNormal.a *= packedNormal.r;
return UnpackDerivativeNormalAG(packedNormal, scale);
}

View File

@@ -0,0 +1,592 @@
#ifndef UNITY_PACKING_INCLUDED
#define UNITY_PACKING_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
//-----------------------------------------------------------------------------
// Normal packing
//-----------------------------------------------------------------------------
real3 PackNormalMaxComponent(real3 n)
{
return (n / Max3(abs(n.x), abs(n.y), abs(n.z))) * 0.5 + 0.5;
}
real3 UnpackNormalMaxComponent(real3 n)
{
return normalize(n * 2.0 - 1.0);
}
// Ref: http://www.vis.uni-stuttgart.de/~engelhts/paper/vmvOctaMaps.pdf "Octahedron Environment Maps"
// Encode with Oct, this function work with any size of output
// return real between [-1, 1]
real2 PackNormalOctRectEncode(real3 n)
{
// Perform planar projection.
real3 p = n * rcp(dot(abs(n), 1.0));
real x = p.x, y = p.y, z = p.z;
// Unfold the octahedron.
// Also correct the aspect ratio from 2:1 to 1:1.
real r = saturate(0.5 - 0.5 * x + 0.5 * y);
real g = x + y;
// Negative hemisphere on the left, positive on the right.
return real2(CopySign(r, z), g);
}
real3 UnpackNormalOctRectEncode(real2 f)
{
real r = f.r, g = f.g;
// Solve for {x, y, z} given {r, g}.
real x = 0.5 + 0.5 * g - abs(r);
real y = g - x;
real z = max(1.0 - abs(x) - abs(y), REAL_EPS); // EPS is absolutely crucial for anisotropy
real3 p = real3(x, y, CopySign(z, r));
return normalize(p);
}
// Ref: http://jcgt.org/published/0003/02/01/paper.pdf "A Survey of Efficient Representations for Independent Unit Vectors"
// Encode with Oct, this function work with any size of output
// return float between [-1, 1]
float2 PackNormalOctQuadEncode(float3 n)
{
//float l1norm = dot(abs(n), 1.0);
//float2 res0 = n.xy * (1.0 / l1norm);
//float2 val = 1.0 - abs(res0.yx);
//return (n.zz < float2(0.0, 0.0) ? (res0 >= 0.0 ? val : -val) : res0);
// Optimized version of above code:
n *= rcp(dot(abs(n), 1.0));
float t = saturate(-n.z);
return n.xy + (n.xy >= 0.0 ? t : -t);
}
float3 UnpackNormalOctQuadEncode(float2 f)
{
float3 n = float3(f.x, f.y, 1.0 - abs(f.x) - abs(f.y));
//float2 val = 1.0 - abs(n.yx);
//n.xy = (n.zz < float2(0.0, 0.0) ? (n.xy >= 0.0 ? val : -val) : n.xy);
// Optimized version of above code:
float t = max(-n.z, 0.0);
n.xy += n.xy >= 0.0 ? -t.xx : t.xx;
return normalize(n);
}
real2 PackNormalHemiOctEncode(real3 n)
{
real l1norm = dot(abs(n), 1.0);
real2 res = n.xy * (1.0 / l1norm);
return real2(res.x + res.y, res.x - res.y);
}
real3 UnpackNormalHemiOctEncode(real2 f)
{
real2 val = real2(f.x + f.y, f.x - f.y) * 0.5;
real3 n = real3(val, 1.0 - dot(abs(val), 1.0));
return normalize(n);
}
// Tetrahedral encoding - Looks like Tetra encoding 10:10 + 2 is similar to oct 11:11, as oct is cheaper prefer it
// To generate the basisNormal below we use these 4 vertex of a regular tetrahedron
// v0 = float3(1.0, 0.0, -1.0 / sqrt(2.0));
// v1 = float3(-1.0, 0.0, -1.0 / sqrt(2.0));
// v2 = float3(0.0, 1.0, 1.0 / sqrt(2.0));
// v3 = float3(0.0, -1.0, 1.0 / sqrt(2.0));
// Then we normalize the average of each face's vertices
// normalize(v0 + v1 + v2), etc...
static const real3 tetraBasisNormal[4] =
{
real3(0., 0.816497, -0.57735),
real3(-0.816497, 0., 0.57735),
real3(0.816497, 0., 0.57735),
real3(0., -0.816497, -0.57735)
};
// Then to get the local matrix (with z axis rotate to basisNormal) use GetLocalFrame(basisNormal[xxx])
static const real3x3 tetraBasisArray[4] =
{
real3x3(-1., 0., 0.,0., 0.57735, 0.816497,0., 0.816497, -0.57735),
real3x3(0., -1., 0.,0.57735, 0., 0.816497,-0.816497, 0., 0.57735),
real3x3(0., 1., 0.,-0.57735, 0., 0.816497,0.816497, 0., 0.57735),
real3x3(1., 0., 0.,0., -0.57735, 0.816497,0., -0.816497, -0.57735)
};
// Return [-1..1] vector2 oriented in plane of the faceIndex of a regular tetrahedron
real2 PackNormalTetraEncode(float3 n, out uint faceIndex)
{
// Retrieve the tetrahedra's face for the normal direction
// It is the one with the greatest dot value with face normal
real dot0 = dot(n, tetraBasisNormal[0]);
real dot1 = dot(n, tetraBasisNormal[1]);
real dot2 = dot(n, tetraBasisNormal[2]);
real dot3 = dot(n, tetraBasisNormal[3]);
real maxi0 = max(dot0, dot1);
real maxi1 = max(dot2, dot3);
real maxi = max(maxi0, maxi1);
// Get the index from the greatest dot
if (maxi == dot0)
faceIndex = 0;
else if (maxi == dot1)
faceIndex = 1;
else if (maxi == dot2)
faceIndex = 2;
else //(maxi == dot3)
faceIndex = 3;
// Rotate n into this local basis
n = mul(tetraBasisArray[faceIndex], n);
// Project n onto the local plane
return n.xy;
}
// Assume f [-1..1]
real3 UnpackNormalTetraEncode(real2 f, uint faceIndex)
{
// Recover n from local plane
real3 n = real3(f.xy, sqrt(1.0 - dot(f.xy, f.xy)));
// Inverse of transform PackNormalTetraEncode (just swap order in mul as we have a rotation)
return mul(n, tetraBasisArray[faceIndex]);
}
// Unpack from normal map
real3 UnpackNormalRGB(real4 packedNormal, real scale = 1.0)
{
real3 normal;
normal.xyz = packedNormal.rgb * 2.0 - 1.0;
normal.xy *= scale;
return normal;
}
real3 UnpackNormalRGBNoScale(real4 packedNormal)
{
return packedNormal.rgb * 2.0 - 1.0;
}
real3 UnpackNormalAG(real4 packedNormal, real scale = 1.0)
{
real3 normal;
normal.xy = packedNormal.ag * 2.0 - 1.0;
normal.z = max(1.0e-16, sqrt(1.0 - saturate(dot(normal.xy, normal.xy))));
// must scale after reconstruction of normal.z which also
// mirrors UnpackNormalRGB(). This does imply normal is not returned
// as a unit length vector but doesn't need it since it will get normalized after TBN transformation.
// If we ever need to blend contributions with built-in shaders for URP
// then we should consider using UnpackDerivativeNormalAG() instead like
// HDRP does since derivatives do not use renormalization and unlike tangent space
// normals allow you to blend, accumulate and scale contributions correctly.
normal.xy *= scale;
return normal;
}
// Unpack normal as DXT5nm (1, y, 0, x) or BC5 (x, y, 0, 1)
real3 UnpackNormalmapRGorAG(real4 packedNormal, real scale = 1.0)
{
// Convert to (?, y, 0, x)
packedNormal.a *= packedNormal.r;
return UnpackNormalAG(packedNormal, scale);
}
real3 UnpackNormal(real4 packedNormal)
{
#if defined(UNITY_ASTC_NORMALMAP_ENCODING)
return UnpackNormalAG(packedNormal, 1.0);
#elif defined(UNITY_NO_DXT5nm)
return UnpackNormalRGBNoScale(packedNormal);
#else
// Compiler will optimize the scale away
return UnpackNormalmapRGorAG(packedNormal, 1.0);
#endif
}
real3 UnpackNormalScale(real4 packedNormal, real bumpScale)
{
#if defined(UNITY_ASTC_NORMALMAP_ENCODING)
return UnpackNormalAG(packedNormal, bumpScale);
#elif defined(UNITY_NO_DXT5nm)
return UnpackNormalRGB(packedNormal, bumpScale);
#else
return UnpackNormalmapRGorAG(packedNormal, bumpScale);
#endif
}
//-----------------------------------------------------------------------------
// HDR packing
//-----------------------------------------------------------------------------
// HDR Packing not defined in GLES2
#if !defined(SHADER_API_GLES)
// Ref: http://realtimecollisiondetection.net/blog/?p=15
real4 PackToLogLuv(real3 vRGB)
{
// M matrix, for encoding
const real3x3 M = real3x3(
0.2209, 0.3390, 0.4184,
0.1138, 0.6780, 0.7319,
0.0102, 0.1130, 0.2969);
real4 vResult;
real3 Xp_Y_XYZp = mul(vRGB, M);
Xp_Y_XYZp = max(Xp_Y_XYZp, real3(1e-6, 1e-6, 1e-6));
vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
real Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
vResult.w = frac(Le);
vResult.z = (Le - (floor(vResult.w * 255.0)) / 255.0) / 255.0;
return vResult;
}
real3 UnpackFromLogLuv(real4 vLogLuv)
{
// Inverse M matrix, for decoding
const real3x3 InverseM = real3x3(
6.0014, -2.7008, -1.7996,
-1.3320, 3.1029, -5.7721,
0.3008, -1.0882, 5.6268);
real Le = vLogLuv.z * 255.0 + vLogLuv.w;
real3 Xp_Y_XYZp;
Xp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);
Xp_Y_XYZp.z = Xp_Y_XYZp.y / vLogLuv.y;
Xp_Y_XYZp.x = vLogLuv.x * Xp_Y_XYZp.z;
real3 vRGB = mul(Xp_Y_XYZp, InverseM);
return max(vRGB, real3(0.0, 0.0, 0.0));
}
// The standard 32-bit HDR color format
uint PackToR11G11B10f(float3 rgb)
{
uint r = (f32tof16(rgb.x) << 17) & 0xFFE00000;
uint g = (f32tof16(rgb.y) << 6) & 0x001FFC00;
uint b = (f32tof16(rgb.z) >> 5) & 0x000003FF;
return r | g | b;
}
float3 UnpackFromR11G11B10f(uint rgb)
{
float r = f16tof32((rgb >> 17) & 0x7FF0);
float g = f16tof32((rgb >> 6) & 0x7FF0);
float b = f16tof32((rgb << 5) & 0x7FE0);
return float3(r, g, b);
}
#endif // SHADER_API_GLES
//-----------------------------------------------------------------------------
// Color packing
//-----------------------------------------------------------------------------
float4 UnpackFromR8G8B8A8(uint rgba)
{
return float4(rgba & 255, (rgba >> 8) & 255, (rgba >> 16) & 255, (rgba >> 24) & 255) * (1.0 / 255);
}
//-----------------------------------------------------------------------------
// Quaternion packing
//-----------------------------------------------------------------------------
// Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4
/*
// This is GCN intrinsic
uint FindBiggestComponent(real4 q)
{
uint xyzIndex = CubeMapFaceID(q.x, q.y, q.z) * 0.5f;
uint wIndex = 3;
bool wBiggest = abs(q.w) > max3(abs(q.x), qbs(q.y), qbs(q.z));
return wBiggest ? wIndex : xyzIndex;
}
// Pack a quaternion into a 10:10:10:2
real4 PackQuat(real4 quat)
{
uint index = FindBiggestComponent(quat);
if (index == 0) quat = quat.yzwx;
if (index == 1) quat = quat.xzwy;
if (index == 2) quat = quat.xywz;
real4 packedQuat;
packedQuat.xyz = quat.xyz * FastSign(quat.w) * sqrt(0.5) + 0.5;
packedQuat.w = index / 3.0;
return packedQuat;
}
*/
// Unpack a quaternion from a 10:10:10:2
real4 UnpackQuat(real4 packedQuat)
{
uint index = (uint)(packedQuat.w * 3.0);
real4 quat;
quat.xyz = packedQuat.xyz * sqrt(2.0) - (1.0 / sqrt(2.0));
quat.w = sqrt(1.0 - saturate(dot(quat.xyz, quat.xyz)));
if (index == 0) quat = quat.wxyz;
if (index == 1) quat = quat.xwyz;
if (index == 2) quat = quat.xywz;
return quat;
}
// Integer and Float packing not defined in GLES2
#if !defined(SHADER_API_GLES)
//-----------------------------------------------------------------------------
// Integer packing
//-----------------------------------------------------------------------------
// Packs an integer stored using at most 'numBits' into a [0..1] real.
real PackInt(uint i, uint numBits)
{
uint maxInt = (1u << numBits) - 1u;
return saturate(i * rcp(maxInt));
}
// Unpacks a [0..1] real into an integer of size 'numBits'.
uint UnpackInt(real f, uint numBits)
{
uint maxInt = (1u << numBits) - 1u;
return (uint)(f * maxInt + 0.5); // Round instead of truncating
}
// Packs a [0..255] integer into a [0..1] real.
real PackByte(uint i)
{
return PackInt(i, 8);
}
// Unpacks a [0..1] real into a [0..255] integer.
uint UnpackByte(real f)
{
return UnpackInt(f, 8);
}
// Packs a [0..65535] integer into a [0..1] real.
real PackShort(uint i)
{
return PackInt(i, 16);
}
// Unpacks a [0..1] real into a [0..65535] integer.
uint UnpackShort(real f)
{
return UnpackInt(f, 16);
}
// Packs 8 lowermost bits of a [0..65535] integer into a [0..1] real.
real PackShortLo(uint i)
{
uint lo = BitFieldExtract(i, 0u, 8u);
return PackInt(lo, 8);
}
// Packs 8 uppermost bits of a [0..65535] integer into a [0..1] real.
real PackShortHi(uint i)
{
uint hi = BitFieldExtract(i, 8u, 8u);
return PackInt(hi, 8);
}
real Pack2Byte(real2 inputs)
{
real2 temp = inputs * real2(255.0, 255.0);
temp.x *= 256.0;
temp = round(temp);
real combined = temp.x + temp.y;
return combined * (1.0 / 65535.0);
}
real2 Unpack2Byte(real inputs)
{
real temp = round(inputs * 65535.0);
real ipart;
real fpart = modf(temp / 256.0, ipart);
real2 result = real2(ipart, round(256.0 * fpart));
return result * (1.0 / real2(255.0, 255.0));
}
// Encode a real in [0..1] and an int in [0..maxi - 1] as a real [0..1] to be store in log2(precision) bit
// maxi must be a power of two and define the number of bit dedicated 0..1 to the int part (log2(maxi))
// Example: precision is 256.0, maxi is 2, i is [0..1] encode on 1 bit. f is [0..1] encode on 7 bit.
// Example: precision is 256.0, maxi is 4, i is [0..3] encode on 2 bit. f is [0..1] encode on 6 bit.
// Example: precision is 256.0, maxi is 8, i is [0..7] encode on 3 bit. f is [0..1] encode on 5 bit.
// ...
// Example: precision is 1024.0, maxi is 8, i is [0..7] encode on 3 bit. f is [0..1] encode on 7 bit.
//...
real PackFloatInt(real f, uint i, real maxi, real precision)
{
// Constant
real precisionMinusOne = precision - 1.0;
real t1 = ((precision / maxi) - 1.0) / precisionMinusOne;
real t2 = (precision / maxi) / precisionMinusOne;
return t1 * f + t2 * real(i);
}
void UnpackFloatInt(real val, real maxi, real precision, out real f, out uint i)
{
// Constant
real precisionMinusOne = precision - 1.0;
real t1 = ((precision / maxi) - 1.0) / precisionMinusOne;
real t2 = (precision / maxi) / precisionMinusOne;
// extract integer part
i = int((val / t2) + rcp(precisionMinusOne)); // + rcp(precisionMinusOne) to deal with precision issue (can't use round() as val contain the floating number
// Now that we have i, solve formula in PackFloatInt for f
//f = (val - t2 * real(i)) / t1 => convert in mads form
f = saturate((-t2 * real(i) + val) / t1); // Saturate in case of precision issue
}
// Define various variante for ease of read
real PackFloatInt8bit(real f, uint i, real maxi)
{
return PackFloatInt(f, i, maxi, 256.0);
}
void UnpackFloatInt8bit(real val, real maxi, out real f, out uint i)
{
UnpackFloatInt(val, maxi, 256.0, f, i);
}
real PackFloatInt10bit(real f, uint i, real maxi)
{
return PackFloatInt(f, i, maxi, 1024.0);
}
void UnpackFloatInt10bit(real val, real maxi, out real f, out uint i)
{
UnpackFloatInt(val, maxi, 1024.0, f, i);
}
real PackFloatInt16bit(real f, uint i, real maxi)
{
return PackFloatInt(f, i, maxi, 65536.0);
}
void UnpackFloatInt16bit(real val, real maxi, out real f, out uint i)
{
UnpackFloatInt(val, maxi, 65536.0, f, i);
}
//-----------------------------------------------------------------------------
// Float packing
//-----------------------------------------------------------------------------
// src must be between 0.0 and 1.0
uint PackFloatToUInt(real src, uint offset, uint numBits)
{
return UnpackInt(src, numBits) << offset;
}
real UnpackUIntToFloat(uint src, uint offset, uint numBits)
{
uint maxInt = (1u << numBits) - 1u;
return real(BitFieldExtract(src, offset, numBits)) * rcp(maxInt);
}
uint PackToR10G10B10A2(real4 rgba)
{
return (PackFloatToUInt(rgba.x, 0, 10) |
PackFloatToUInt(rgba.y, 10, 10) |
PackFloatToUInt(rgba.z, 20, 10) |
PackFloatToUInt(rgba.w, 30, 2));
}
real4 UnpackFromR10G10B10A2(uint rgba)
{
real4 output;
output.x = UnpackUIntToFloat(rgba, 0, 10);
output.y = UnpackUIntToFloat(rgba, 10, 10);
output.z = UnpackUIntToFloat(rgba, 20, 10);
output.w = UnpackUIntToFloat(rgba, 30, 2);
return output;
}
// Both the input and the output are in the [0, 1] range.
real2 PackFloatToR8G8(real f)
{
uint i = UnpackShort(f);
return real2(PackShortLo(i), PackShortHi(i));
}
// Both the input and the output are in the [0, 1] range.
real UnpackFloatFromR8G8(real2 f)
{
uint lo = UnpackByte(f.x);
uint hi = UnpackByte(f.y);
uint cb = (hi << 8) + lo;
return PackShort(cb);
}
// Pack float2 (each of 12 bit) in 888
float3 PackFloat2To888(float2 f)
{
uint2 i = (uint2)(f * 4095.5);
uint2 hi = i >> 8;
uint2 lo = i & 255;
// 8 bit in lo, 4 bit in hi
uint3 cb = uint3(lo, hi.x | (hi.y << 4));
return cb / 255.0;
}
// Unpack 2 float of 12bit packed into a 888
float2 Unpack888ToFloat2(float3 x)
{
uint3 i = (uint3)(x * 255.5); // +0.5 to fix precision error on iOS
// 8 bit in lo, 4 bit in hi
uint hi = i.z >> 4;
uint lo = i.z & 15;
uint2 cb = i.xy | uint2(lo << 8, hi << 8);
return cb / 4095.0;
}
#endif // SHADER_API_GLES
// Pack 2 float values from the [0, 1] range, to an 8 bits float from the [0, 1] range
float PackFloat2To8(float2 f)
{
float x_expanded = f.x * 15.0; // f.x encoded over 4 bits, can have 2^4 = 16 distinct values mapped to [0, 1, ..., 15]
float y_expanded = f.y * 15.0; // f.y encoded over 4 bits, can have 2^4 = 16 distinct values mapped to [0, 1, ..., 15]
float x_y_expanded = x_expanded * 16.0 + y_expanded; // f.x encoded over higher bits, f.y encoded over the lower bits - x_y values in range [0, 1, ..., 255]
return x_y_expanded / 255.0;
// above 4 lines equivalent to:
//return (16.0 * f.x + f.y) / 17.0;
}
// Unpack 2 float values from the [0, 1] range, packed in an 8 bits float from the [0, 1] range
float2 Unpack8ToFloat2(float f)
{
float x_y_expanded = 255.0 * f;
float x_expanded = floor(x_y_expanded / 16.0);
float y_expanded = x_y_expanded - 16.0 * x_expanded;
float x = x_expanded / 15.0;
float y = y_expanded / 15.0;
return float2(x, y);
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_PACKING_INCLUDED

View File

@@ -0,0 +1,44 @@
#ifndef UNIVERSAL_PARALLAX_MAPPING_INCLUDED
#define UNIVERSAL_PARALLAX_MAPPING_INCLUDED
// Return view direction in tangent space, make sure tangentWS.w is already multiplied by GetOddNegativeScale()
half3 GetViewDirectionTangentSpace(half4 tangentWS, half3 normalWS, half3 viewDirWS)
{
// must use interpolated tangent, bitangent and normal before they are normalized in the pixel shader.
half3 unnormalizedNormalWS = normalWS;
const half renormFactor = 1.0 / length(unnormalizedNormalWS);
// use bitangent on the fly like in hdrp
// IMPORTANT! If we ever support Flip on double sided materials ensure bitangent and tangent are NOT flipped.
half crossSign = (tangentWS.w > 0.0 ? 1.0 : -1.0); // we do not need to multiple GetOddNegativeScale() here, as it is done in vertex shader
half3 bitang = crossSign * cross(normalWS.xyz, tangentWS.xyz);
half3 WorldSpaceNormal = renormFactor * normalWS.xyz; // we want a unit length Normal Vector node in shader graph
// to preserve mikktspace compliance we use same scale renormFactor as was used on the normal.
// This is explained in section 2.2 in "surface gradient based bump mapping framework"
half3 WorldSpaceTangent = renormFactor * tangentWS.xyz;
half3 WorldSpaceBiTangent = renormFactor * bitang;
half3x3 tangentSpaceTransform = half3x3(WorldSpaceTangent, WorldSpaceBiTangent, WorldSpaceNormal);
half3 viewDirTS = mul(tangentSpaceTransform, viewDirWS);
return viewDirTS;
}
half2 ParallaxOffset1Step(half height, half amplitude, half3 viewDirTS)
{
height = height * amplitude - amplitude / 2.0;
half3 v = normalize(viewDirTS);
v.z += 0.42;
return height * (v.xy / v.z);
}
float2 ParallaxMapping(TEXTURE2D_PARAM(heightMap, sampler_heightMap), half3 viewDirTS, half scale, float2 uv)
{
half h = SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, uv).g;
float2 offset = ParallaxOffset1Step(h, scale, viewDirTS);
return offset;
}
#endif // UNIVERSAL_PARALLAX_MAPPING_INCLUDED

View File

@@ -0,0 +1,128 @@
// This is implementation of parallax occlusion mapping (POM)
// This function require that the caller define a callback for the height sampling name ComputePerPixelHeightDisplacement
// A PerPixelHeightDisplacementParam is used to provide all data necessary to calculate the heights to ComputePerPixelHeightDisplacement it doesn't need to be
// visible by the POM algorithm.
// This function is compatible with tiled uv.
// it return the offset to apply to the UVSet provide in PerPixelHeightDisplacementParam
// viewDirTS is view vector in texture space matching the UVSet
// ref: https://www.gamedev.net/resources/_/technical/graphics-programming-and-theory/a-closer-look-at-parallax-occlusion-mapping-r3262
#ifndef POM_USER_DATA_PARAMETERS
#define POM_USER_DATA_PARAMETERS
#endif
#ifndef POM_USER_DATA_ARGUMENTS
#define POM_USER_DATA_ARGUMENTS
#endif
real2
#ifdef POM_NAME_ID
MERGE_NAME(ParallaxOcclusionMapping,POM_NAME_ID)
#else
ParallaxOcclusionMapping
#endif
(real lod, real lodThreshold, int numSteps, real3 viewDirTS, PerPixelHeightDisplacementParam ppdParam, out real outHeight POM_USER_DATA_PARAMETERS)
{
// Convention: 1.0 is top, 0.0 is bottom - POM is always inward, no extrusion
real stepSize = 1.0 / (real)numSteps;
// View vector is from the point to the camera, but we want to raymarch from camera to point, so reverse the sign
// The length of viewDirTS vector determines the furthest amount of displacement:
// real parallaxLimit = -length(viewDirTS.xy) / viewDirTS.z;
// real2 parallaxDir = normalize(Out.viewDirTS.xy);
// real2 parallaxMaxOffsetTS = parallaxDir * parallaxLimit;
// Above code simplify to
real2 parallaxMaxOffsetTS = (viewDirTS.xy / -viewDirTS.z);
real2 texOffsetPerStep = stepSize * parallaxMaxOffsetTS;
// Do a first step before the loop to init all value correctly
real2 texOffsetCurrent = real2(0.0, 0.0);
real prevHeight = ComputePerPixelHeightDisplacement(texOffsetCurrent, lod, ppdParam POM_USER_DATA_ARGUMENTS);
texOffsetCurrent += texOffsetPerStep;
real currHeight = ComputePerPixelHeightDisplacement(texOffsetCurrent, lod, ppdParam POM_USER_DATA_ARGUMENTS);
real rayHeight = 1.0 - stepSize; // Start at top less one sample
// Linear search
for (int stepIndex = 0; stepIndex < numSteps; ++stepIndex)
{
// Have we found a height below our ray height ? then we have an intersection
if (currHeight > rayHeight)
break; // end the loop
prevHeight = currHeight;
rayHeight -= stepSize;
texOffsetCurrent += texOffsetPerStep;
// Sample height map which in this case is stored in the alpha channel of the normal map:
currHeight = ComputePerPixelHeightDisplacement(texOffsetCurrent, lod, ppdParam POM_USER_DATA_ARGUMENTS);
}
// Found below and above points, now perform line interesection (ray) with piecewise linear heightfield approximation
// Refine the search with secant method
#define POM_SECANT_METHOD 1
#if POM_SECANT_METHOD
real pt0 = rayHeight + stepSize;
real pt1 = rayHeight;
real delta0 = pt0 - prevHeight;
real delta1 = pt1 - currHeight;
real delta;
real2 offset;
// Secant method to affine the search
// Ref: Faster Relief Mapping Using the Secant Method - Eric Risser
for (int i = 0; i < 3; ++i)
{
// intersectionHeight is the height [0..1] for the intersection between view ray and heightfield line
real intersectionHeight = (pt0 * delta1 - pt1 * delta0) / (delta1 - delta0);
// Retrieve offset require to find this intersectionHeight
offset = (1 - intersectionHeight) * texOffsetPerStep * numSteps;
currHeight = ComputePerPixelHeightDisplacement(offset, lod, ppdParam POM_USER_DATA_ARGUMENTS);
delta = intersectionHeight - currHeight;
if (abs(delta) <= 0.01)
break;
// intersectionHeight < currHeight => new lower bounds
if (delta < 0.0)
{
delta1 = delta;
pt1 = intersectionHeight;
}
else
{
delta0 = delta;
pt0 = intersectionHeight;
}
}
#else // regular POM intersection
//real pt0 = rayHeight + stepSize;
//real pt1 = rayHeight;
//real delta0 = pt0 - prevHeight;
//real delta1 = pt1 - currHeight;
//real intersectionHeight = (pt0 * delta1 - pt1 * delta0) / (delta1 - delta0);
//real2 offset = (1 - intersectionHeight) * texOffsetPerStep * numSteps;
// A bit more optimize
real delta0 = currHeight - rayHeight;
real delta1 = (rayHeight + stepSize) - prevHeight;
real ratio = delta0 / (delta0 + delta1);
real2 offset = texOffsetCurrent - ratio * texOffsetPerStep;
currHeight = ComputePerPixelHeightDisplacement(offset, lod, ppdParam POM_USER_DATA_ARGUMENTS);
#endif
outHeight = currHeight;
// Fade the effect with lod (allow to avoid pop when switching to a discrete LOD mesh)
offset *= (1.0 - saturate(lod - lodThreshold));
return offset;
}

View File

@@ -0,0 +1,75 @@
#ifndef UNITY_PHYSICAL_CAMERA_INCLUDED
#define UNITY_PHYSICAL_CAMERA_INCLUDED
// Has to be kept in sync with ColorUtils.cs
// References:
// "Moving Frostbite to PBR" (Sebastien Lagarde & Charles de Rousiers)
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
// "Implementing a Physically Based Camera" (Padraic Hennessy)
// https://placeholderart.wordpress.com/2014/11/16/implementing-a-physically-based-camera-understanding-exposure/
float ComputeEV100(float aperture, float shutterSpeed, float ISO)
{
// EV number is defined as:
// 2^ EV_s = N^2 / t and EV_s = EV_100 + log2 (S /100)
// This gives
// EV_s = log2 (N^2 / t)
// EV_100 + log2 (S /100) = log2 (N^2 / t)
// EV_100 = log2 (N^2 / t) - log2 (S /100)
// EV_100 = log2 (N^2 / t . 100 / S)
return log2((aperture * aperture) / shutterSpeed * 100.0 / ISO);
}
float ComputeEV100FromAvgLuminance(float avgLuminance, float calibrationConstant)
{
const float K = calibrationConstant;
return log2(avgLuminance * 100.0 / K);
}
float ComputeEV100FromAvgLuminance(float avgLuminance)
{
// We later use the middle gray at 12.7% in order to have
// a middle gray at 18% with a sqrt(2) room for specular highlights
// But here we deal with the spot meter measuring the middle gray
// which is fixed at 12.5 for matching standard camera
// constructor settings (i.e. calibration constant K = 12.5)
// Reference: http://en.wikipedia.org/wiki/Film_speed
const float K = 12.5; // Reflected-light meter calibration constant
return ComputeEV100FromAvgLuminance(avgLuminance, K);
}
float ConvertEV100ToExposure(float EV100, float exposureScale)
{
// Compute the maximum luminance possible with H_sbs sensitivity
// maxLum = 78 / ( S * q ) * N^2 / t
// = 78 / ( S * q ) * 2^ EV_100
// = 78 / (100 * s_LensAttenuation) * 2^ EV_100
// = exposureScale * 2^ EV
// Reference: http://en.wikipedia.org/wiki/Film_speed
float maxLuminance = exposureScale * pow(2.0, EV100);
return 1.0 / maxLuminance;
}
float ConvertEV100ToExposure(float EV100)
{
const float exposureScale = 1.2;
return ConvertEV100ToExposure(EV100, exposureScale);
}
float ComputeISO(float aperture, float shutterSpeed, float targetEV100)
{
// Compute the required ISO to reach the target EV100
return ((aperture * aperture) * 100.0) / (shutterSpeed * pow(2.0, targetEV100));
}
float ComputeLuminanceAdaptation(float previousLuminance, float currentLuminance, float speedDarkToLight, float speedLightToDark, float deltaTime)
{
float delta = currentLuminance - previousLuminance;
float speed = delta > 0.0 ? speedDarkToLight : speedLightToDark;
// Exponential decay
return previousLuminance + delta * (1.0 - exp2(-deltaTime * speed));
}
#endif // UNITY_PHYSICAL_CAMERA_INCLUDED

View File

@@ -0,0 +1,104 @@
#ifndef UNITY_RANDOM_INCLUDED
#define UNITY_RANDOM_INCLUDED
#if !defined(SHADER_API_GLES)
// A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm.
uint JenkinsHash(uint x)
{
x += (x << 10u);
x ^= (x >> 6u);
x += (x << 3u);
x ^= (x >> 11u);
x += (x << 15u);
return x;
}
// Compound versions of the hashing algorithm.
uint JenkinsHash(uint2 v)
{
return JenkinsHash(v.x ^ JenkinsHash(v.y));
}
uint JenkinsHash(uint3 v)
{
return JenkinsHash(v.x ^ JenkinsHash(v.yz));
}
uint JenkinsHash(uint4 v)
{
return JenkinsHash(v.x ^ JenkinsHash(v.yzw));
}
// Construct a float with half-open range [0, 1) using low 23 bits.
// All zeros yields 0, all ones yields the next smallest representable value below 1.
float ConstructFloat(int m) {
const int ieeeMantissa = 0x007FFFFF; // Binary FP32 mantissa bitmask
const int ieeeOne = 0x3F800000; // 1.0 in FP32 IEEE
m &= ieeeMantissa; // Keep only mantissa bits (fractional part)
m |= ieeeOne; // Add fractional part to 1.0
float f = asfloat(m); // Range [1, 2)
return f - 1; // Range [0, 1)
}
float ConstructFloat(uint m)
{
return ConstructFloat(asint(m));
}
// Pseudo-random value in half-open range [0, 1). The distribution is reasonably uniform.
// Ref: https://stackoverflow.com/a/17479300
float GenerateHashedRandomFloat(uint x)
{
return ConstructFloat(JenkinsHash(x));
}
float GenerateHashedRandomFloat(uint2 v)
{
return ConstructFloat(JenkinsHash(v));
}
float GenerateHashedRandomFloat(uint3 v)
{
return ConstructFloat(JenkinsHash(v));
}
float GenerateHashedRandomFloat(uint4 v)
{
return ConstructFloat(JenkinsHash(v));
}
float Hash(uint s)
{
s = s ^ 2747636419u;
s = s * 2654435769u;
s = s ^ (s >> 16);
s = s * 2654435769u;
s = s ^ (s >> 16);
s = s * 2654435769u;
return float(s) * rcp(4294967296.0); // 2^-32
}
float2 InitRandom(float2 input)
{
float2 r;
r.x = Hash(uint(input.x * UINT_MAX));
r.y = Hash(uint(input.y * UINT_MAX));
return r;
}
#endif // SHADER_API_GLES
//From Next Generation Post Processing in Call of Duty: Advanced Warfare [Jimenez 2014]
// http://advances.realtimerendering.com/s2014/index.html
float InterleavedGradientNoise(float2 pixCoord, int frameCount)
{
const float3 magic = float3(0.06711056f, 0.00583715f, 52.9829189f);
float2 frameMagicScale = float2(2.083f, 4.867f);
pixCoord += frameCount * frameMagicScale;
return frac(magic.z * frac(dot(pixCoord, magic.xy)));
}
#endif // UNITY_RANDOM_INCLUDED

View File

@@ -0,0 +1,70 @@
#ifndef UNITY_REFRACTION_INCLUDED
#define UNITY_REFRACTION_INCLUDED
//-----------------------------------------------------------------------------
// Util refraction
//-----------------------------------------------------------------------------
struct RefractionModelResult
{
real dist; // length of the transmission during refraction through the shape
float3 positionWS; // out ray position
real3 rayWS; // out ray direction
};
RefractionModelResult RefractionModelSphere(real3 V, float3 positionWS, real3 normalWS, real ior, real thickness)
{
// Sphere shape model:
// We approximate locally the shape of the object as sphere, that is tangent to the shape.
// The sphere has a diameter of {thickness}
// The center of the sphere is at {positionWS} - {normalWS} * {thickness} * 0.5
//
// So the light is refracted twice: in and out of the tangent sphere
// First refraction (tangent sphere in)
// Refracted ray
real3 R1 = refract(-V, normalWS, 1.0 / ior);
// Center of the tangent sphere
real3 C = positionWS - normalWS * thickness * 0.5;
// Second refraction (tangent sphere out)
real NoR1 = dot(normalWS, R1);
// Optical depth within the sphere
real dist = -NoR1 * thickness;
// Out hit point in the tangent sphere
real3 P1 = positionWS + R1 * dist;
// Out normal
real3 N1 = normalize(C - P1);
// Out refracted ray
real3 R2 = refract(R1, N1, ior);
real N1oR2 = dot(N1, R2);
real VoR1 = dot(V, R1);
RefractionModelResult result;
result.dist = dist;
result.positionWS = P1;
result.rayWS = R2;
return result;
}
RefractionModelResult RefractionModelBox(real3 V, float3 positionWS, real3 normalWS, real ior, real thickness)
{
// Plane shape model:
// We approximate locally the shape of the object as a plane with normal {normalWS} at {positionWS}
// with a thickness {thickness}
// Refracted ray
real3 R = refract(-V, normalWS, 1.0 / ior);
// Optical depth within the thin plane
real dist = thickness / max(dot(R, -normalWS), 1e-5f);
RefractionModelResult result;
result.dist = dist;
result.positionWS = positionWS + R * dist;
result.rayWS = -V;
return result;
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef UNITY_SDF2D_INCLUDED
#define UNITY_SDF2D_INCLUDED
// Ref: https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
float CircleSDF(float2 position, float radius)
{
return length(position) - radius;
}
float RectangleSDF(float2 position, float2 bound)
{
float2 d = abs(position) - bound;
return length(max(d, float2(0, 0))) + min(max(d.x, d.y), 0.0);
}
float EllipseSDF(float2 position, float2 r)
{
float2 p = position;
float2 r2 = r*r;
float k0 = length(p/r);
float k1 = length(p/r2);
return k0*(k0 - 1.0)/k1;
}
#endif // UNITY_SDF2D_INCLUDED

View File

@@ -0,0 +1,306 @@
#ifndef UNITY_FIBONACCI_INCLUDED
#define UNITY_FIBONACCI_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
// Computes a point using the Fibonacci sequence of length N.
// Input: Fib[N - 1], Fib[N - 2], and the index 'i' of the point.
// Ref: Efficient Quadrature Rules for Illumination Integrals
real2 Fibonacci2dSeq(real fibN1, real fibN2, uint i)
{
// 3 cycles on GCN if 'fibN1' and 'fibN2' are known at compile time.
// N.b.: According to Swinbank and Pusser [SP06], the uniformity of the distribution
// can be slightly improved by introducing an offset of 1/N to the Z (or R) coordinates.
return real2(i / fibN1 + (0.5 / fibN1), frac(i * (fibN2 / fibN1)));
}
#define GOLDEN_RATIO 1.618033988749895
#define GOLDEN_ANGLE 2.399963229728653
// Replaces the Fibonacci sequence in Fibonacci2dSeq() with the Golden ratio.
real2 Golden2dSeq(uint i, real n)
{
// GoldenAngle = 2 * Pi * (1 - 1 / GoldenRatio).
// We can drop the "1 -" part since all it does is reverse the orientation.
return real2(i / n + (0.5 / n), frac(i * rcp(GOLDEN_RATIO)));
}
static const uint k_FibonacciSeq[] = {
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181
};
static const real2 k_Fibonacci2dSeq21[] = {
real2(0.02380952, 0.00000000),
real2(0.07142857, 0.61904764),
real2(0.11904762, 0.23809528),
real2(0.16666667, 0.85714293),
real2(0.21428572, 0.47619057),
real2(0.26190478, 0.09523821),
real2(0.30952382, 0.71428585),
real2(0.35714287, 0.33333349),
real2(0.40476191, 0.95238113),
real2(0.45238096, 0.57142878),
real2(0.50000000, 0.19047642),
real2(0.54761904, 0.80952406),
real2(0.59523809, 0.42857170),
real2(0.64285713, 0.04761887),
real2(0.69047618, 0.66666698),
real2(0.73809522, 0.28571510),
real2(0.78571427, 0.90476227),
real2(0.83333331, 0.52380943),
real2(0.88095236, 0.14285755),
real2(0.92857140, 0.76190567),
real2(0.97619045, 0.38095284)
};
static const real2 k_Fibonacci2dSeq34[] = {
real2(0.01470588, 0.00000000),
real2(0.04411765, 0.61764705),
real2(0.07352941, 0.23529410),
real2(0.10294118, 0.85294116),
real2(0.13235295, 0.47058821),
real2(0.16176471, 0.08823538),
real2(0.19117647, 0.70588231),
real2(0.22058824, 0.32352924),
real2(0.25000000, 0.94117641),
real2(0.27941176, 0.55882359),
real2(0.30882353, 0.17647076),
real2(0.33823529, 0.79411745),
real2(0.36764705, 0.41176462),
real2(0.39705881, 0.02941132),
real2(0.42647058, 0.64705849),
real2(0.45588234, 0.26470566),
real2(0.48529410, 0.88235283),
real2(0.51470590, 0.50000000),
real2(0.54411763, 0.11764717),
real2(0.57352942, 0.73529434),
real2(0.60294116, 0.35294151),
real2(0.63235295, 0.97058773),
real2(0.66176468, 0.58823490),
real2(0.69117647, 0.20588207),
real2(0.72058821, 0.82352924),
real2(0.75000000, 0.44117641),
real2(0.77941179, 0.05882263),
real2(0.80882353, 0.67646980),
real2(0.83823532, 0.29411697),
real2(0.86764705, 0.91176414),
real2(0.89705884, 0.52941132),
real2(0.92647058, 0.14705849),
real2(0.95588237, 0.76470566),
real2(0.98529410, 0.38235283)
};
static const real2 k_Fibonacci2dSeq55[] = {
real2(0.00909091, 0.00000000),
real2(0.02727273, 0.61818182),
real2(0.04545455, 0.23636365),
real2(0.06363636, 0.85454547),
real2(0.08181818, 0.47272730),
real2(0.10000000, 0.09090900),
real2(0.11818182, 0.70909095),
real2(0.13636364, 0.32727289),
real2(0.15454546, 0.94545460),
real2(0.17272727, 0.56363630),
real2(0.19090909, 0.18181801),
real2(0.20909090, 0.80000019),
real2(0.22727273, 0.41818190),
real2(0.24545455, 0.03636360),
real2(0.26363635, 0.65454578),
real2(0.28181818, 0.27272701),
real2(0.30000001, 0.89090919),
real2(0.31818181, 0.50909138),
real2(0.33636364, 0.12727261),
real2(0.35454544, 0.74545479),
real2(0.37272727, 0.36363602),
real2(0.39090911, 0.98181820),
real2(0.40909091, 0.60000038),
real2(0.42727274, 0.21818161),
real2(0.44545454, 0.83636379),
real2(0.46363637, 0.45454597),
real2(0.48181817, 0.07272720),
real2(0.50000000, 0.69090843),
real2(0.51818180, 0.30909157),
real2(0.53636366, 0.92727280),
real2(0.55454546, 0.54545403),
real2(0.57272726, 0.16363716),
real2(0.59090906, 0.78181839),
real2(0.60909092, 0.39999962),
real2(0.62727273, 0.01818275),
real2(0.64545453, 0.63636398),
real2(0.66363639, 0.25454521),
real2(0.68181819, 0.87272835),
real2(0.69999999, 0.49090958),
real2(0.71818179, 0.10909081),
real2(0.73636365, 0.72727203),
real2(0.75454545, 0.34545517),
real2(0.77272725, 0.96363640),
real2(0.79090911, 0.58181763),
real2(0.80909091, 0.20000076),
real2(0.82727271, 0.81818199),
real2(0.84545457, 0.43636322),
real2(0.86363637, 0.05454636),
real2(0.88181818, 0.67272758),
real2(0.89999998, 0.29090881),
real2(0.91818184, 0.90909195),
real2(0.93636364, 0.52727318),
real2(0.95454544, 0.14545441),
real2(0.97272730, 0.76363754),
real2(0.99090910, 0.38181686)
};
static const real2 k_Fibonacci2dSeq89[] = {
real2(0.00561798, 0.00000000),
real2(0.01685393, 0.61797750),
real2(0.02808989, 0.23595500),
real2(0.03932584, 0.85393250),
real2(0.05056180, 0.47191000),
real2(0.06179775, 0.08988762),
real2(0.07303371, 0.70786500),
real2(0.08426967, 0.32584238),
real2(0.09550562, 0.94382000),
real2(0.10674157, 0.56179762),
real2(0.11797753, 0.17977524),
real2(0.12921348, 0.79775238),
real2(0.14044943, 0.41573000),
real2(0.15168539, 0.03370762),
real2(0.16292135, 0.65168476),
real2(0.17415731, 0.26966286),
real2(0.18539326, 0.88764000),
real2(0.19662921, 0.50561714),
real2(0.20786516, 0.12359524),
real2(0.21910113, 0.74157238),
real2(0.23033708, 0.35955048),
real2(0.24157304, 0.97752762),
real2(0.25280899, 0.59550476),
real2(0.26404494, 0.21348286),
real2(0.27528089, 0.83146000),
real2(0.28651685, 0.44943714),
real2(0.29775280, 0.06741524),
real2(0.30898875, 0.68539238),
real2(0.32022473, 0.30336952),
real2(0.33146068, 0.92134666),
real2(0.34269664, 0.53932571),
real2(0.35393259, 0.15730286),
real2(0.36516854, 0.77528000),
real2(0.37640449, 0.39325714),
real2(0.38764045, 0.01123428),
real2(0.39887640, 0.62921333),
real2(0.41011235, 0.24719048),
real2(0.42134830, 0.86516762),
real2(0.43258426, 0.48314476),
real2(0.44382024, 0.10112190),
real2(0.45505619, 0.71910095),
real2(0.46629214, 0.33707809),
real2(0.47752810, 0.95505524),
real2(0.48876405, 0.57303238),
real2(0.50000000, 0.19100952),
real2(0.51123595, 0.80898666),
real2(0.52247190, 0.42696571),
real2(0.53370786, 0.04494286),
real2(0.54494381, 0.66292000),
real2(0.55617976, 0.28089714),
real2(0.56741571, 0.89887428),
real2(0.57865167, 0.51685333),
real2(0.58988762, 0.13483047),
real2(0.60112357, 0.75280762),
real2(0.61235952, 0.37078476),
real2(0.62359548, 0.98876190),
real2(0.63483149, 0.60673904),
real2(0.64606744, 0.22471619),
real2(0.65730339, 0.84269333),
real2(0.66853935, 0.46067429),
real2(0.67977530, 0.07865143),
real2(0.69101125, 0.69662857),
real2(0.70224720, 0.31460571),
real2(0.71348315, 0.93258286),
real2(0.72471911, 0.55056000),
real2(0.73595506, 0.16853714),
real2(0.74719101, 0.78651428),
real2(0.75842696, 0.40449142),
real2(0.76966292, 0.02246857),
real2(0.78089887, 0.64044571),
real2(0.79213482, 0.25842667),
real2(0.80337077, 0.87640381),
real2(0.81460673, 0.49438095),
real2(0.82584268, 0.11235809),
real2(0.83707863, 0.73033524),
real2(0.84831458, 0.34831238),
real2(0.85955054, 0.96628952),
real2(0.87078649, 0.58426666),
real2(0.88202250, 0.20224380),
real2(0.89325845, 0.82022095),
real2(0.90449440, 0.43820190),
real2(0.91573036, 0.05617905),
real2(0.92696631, 0.67415619),
real2(0.93820226, 0.29213333),
real2(0.94943821, 0.91011047),
real2(0.96067417, 0.52808762),
real2(0.97191012, 0.14606476),
real2(0.98314607, 0.76404190),
real2(0.99438202, 0.38201904)
};
// Loads elements from one of the precomputed tables for sample counts of 21, 34, 55, and 89.
// Computes sample positions at runtime otherwise.
// Sample count must be a Fibonacci number (see 'k_FibonacciSeq').
real2 Fibonacci2d(uint i, uint sampleCount)
{
switch (sampleCount)
{
case 21: return k_Fibonacci2dSeq21[i];
case 34: return k_Fibonacci2dSeq34[i];
case 55: return k_Fibonacci2dSeq55[i];
case 89: return k_Fibonacci2dSeq89[i];
default:
{
uint fibN1 = sampleCount;
uint fibN2 = sampleCount;
// These are all constants, so this loop will be optimized away.
for (uint j = 1; j < 20; j++)
{
if (k_FibonacciSeq[j] == fibN1)
{
fibN2 = k_FibonacciSeq[j - 1];
}
}
return Fibonacci2dSeq(fibN1, fibN2, i);
}
}
}
real2 SampleDiskGolden(uint i, uint sampleCount)
{
real2 f = Golden2dSeq(i, sampleCount);
return real2(sqrt(f.x), TWO_PI * f.y);
}
// Returns the radius as the X coordinate, and the angle as the Y coordinate.
real2 SampleDiskFibonacci(uint i, uint sampleCount)
{
real2 f = Fibonacci2d(i, sampleCount);
return real2(sqrt(f.x), TWO_PI * f.y);
}
// Returns the zenith as the X coordinate, and the azimuthal angle as the Y coordinate.
real2 SampleHemisphereFibonacci(uint i, uint sampleCount)
{
real2 f = Fibonacci2d(i, sampleCount);
return real2(1 - f.x, TWO_PI * f.y);
}
// Returns the zenith as the X coordinate, and the azimuthal angle as the Y coordinate.
real2 SampleSphereFibonacci(uint i, uint sampleCount)
{
real2 f = Fibonacci2d(i, sampleCount);
return real2(1 - 2 * f.x, TWO_PI * f.y);
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_FIBONACCI_INCLUDED

View File

@@ -0,0 +1,431 @@
#ifndef UNITY_HAMMERSLEY_INCLUDED
#define UNITY_HAMMERSLEY_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
// Ref: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
uint ReverseBits32(uint bits)
{
#if (SHADER_TARGET >= 45)
return reversebits(bits);
#else
bits = (bits << 16) | (bits >> 16);
bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
return bits;
#endif
}
real VanDerCorputBase2(uint i)
{
return ReverseBits32(i) * rcp(4294967296.0); // 2^-32
}
real2 Hammersley2dSeq(uint i, uint sequenceLength)
{
return real2(real(i) / real(sequenceLength), VanDerCorputBase2(i));
}
static const real2 k_Hammersley2dSeq16[] = {
real2(0.00000000, 0.00000000),
real2(0.06250000, 0.50000000),
real2(0.12500000, 0.25000000),
real2(0.18750000, 0.75000000),
real2(0.25000000, 0.12500000),
real2(0.31250000, 0.62500000),
real2(0.37500000, 0.37500000),
real2(0.43750000, 0.87500000),
real2(0.50000000, 0.06250000),
real2(0.56250000, 0.56250000),
real2(0.62500000, 0.31250000),
real2(0.68750000, 0.81250000),
real2(0.75000000, 0.18750000),
real2(0.81250000, 0.68750000),
real2(0.87500000, 0.43750000),
real2(0.93750000, 0.93750000)
};
static const real2 k_Hammersley2dSeq32[] = {
real2(0.00000000, 0.00000000),
real2(0.03125000, 0.50000000),
real2(0.06250000, 0.25000000),
real2(0.09375000, 0.75000000),
real2(0.12500000, 0.12500000),
real2(0.15625000, 0.62500000),
real2(0.18750000, 0.37500000),
real2(0.21875000, 0.87500000),
real2(0.25000000, 0.06250000),
real2(0.28125000, 0.56250000),
real2(0.31250000, 0.31250000),
real2(0.34375000, 0.81250000),
real2(0.37500000, 0.18750000),
real2(0.40625000, 0.68750000),
real2(0.43750000, 0.43750000),
real2(0.46875000, 0.93750000),
real2(0.50000000, 0.03125000),
real2(0.53125000, 0.53125000),
real2(0.56250000, 0.28125000),
real2(0.59375000, 0.78125000),
real2(0.62500000, 0.15625000),
real2(0.65625000, 0.65625000),
real2(0.68750000, 0.40625000),
real2(0.71875000, 0.90625000),
real2(0.75000000, 0.09375000),
real2(0.78125000, 0.59375000),
real2(0.81250000, 0.34375000),
real2(0.84375000, 0.84375000),
real2(0.87500000, 0.21875000),
real2(0.90625000, 0.71875000),
real2(0.93750000, 0.46875000),
real2(0.96875000, 0.96875000)
};
static const real2 k_Hammersley2dSeq64[] = {
real2(0.00000000, 0.00000000),
real2(0.01562500, 0.50000000),
real2(0.03125000, 0.25000000),
real2(0.04687500, 0.75000000),
real2(0.06250000, 0.12500000),
real2(0.07812500, 0.62500000),
real2(0.09375000, 0.37500000),
real2(0.10937500, 0.87500000),
real2(0.12500000, 0.06250000),
real2(0.14062500, 0.56250000),
real2(0.15625000, 0.31250000),
real2(0.17187500, 0.81250000),
real2(0.18750000, 0.18750000),
real2(0.20312500, 0.68750000),
real2(0.21875000, 0.43750000),
real2(0.23437500, 0.93750000),
real2(0.25000000, 0.03125000),
real2(0.26562500, 0.53125000),
real2(0.28125000, 0.28125000),
real2(0.29687500, 0.78125000),
real2(0.31250000, 0.15625000),
real2(0.32812500, 0.65625000),
real2(0.34375000, 0.40625000),
real2(0.35937500, 0.90625000),
real2(0.37500000, 0.09375000),
real2(0.39062500, 0.59375000),
real2(0.40625000, 0.34375000),
real2(0.42187500, 0.84375000),
real2(0.43750000, 0.21875000),
real2(0.45312500, 0.71875000),
real2(0.46875000, 0.46875000),
real2(0.48437500, 0.96875000),
real2(0.50000000, 0.01562500),
real2(0.51562500, 0.51562500),
real2(0.53125000, 0.26562500),
real2(0.54687500, 0.76562500),
real2(0.56250000, 0.14062500),
real2(0.57812500, 0.64062500),
real2(0.59375000, 0.39062500),
real2(0.60937500, 0.89062500),
real2(0.62500000, 0.07812500),
real2(0.64062500, 0.57812500),
real2(0.65625000, 0.32812500),
real2(0.67187500, 0.82812500),
real2(0.68750000, 0.20312500),
real2(0.70312500, 0.70312500),
real2(0.71875000, 0.45312500),
real2(0.73437500, 0.95312500),
real2(0.75000000, 0.04687500),
real2(0.76562500, 0.54687500),
real2(0.78125000, 0.29687500),
real2(0.79687500, 0.79687500),
real2(0.81250000, 0.17187500),
real2(0.82812500, 0.67187500),
real2(0.84375000, 0.42187500),
real2(0.85937500, 0.92187500),
real2(0.87500000, 0.10937500),
real2(0.89062500, 0.60937500),
real2(0.90625000, 0.35937500),
real2(0.92187500, 0.85937500),
real2(0.93750000, 0.23437500),
real2(0.95312500, 0.73437500),
real2(0.96875000, 0.48437500),
real2(0.98437500, 0.98437500)
};
static const real2 k_Hammersley2dSeq256[] = {
real2(0.00000000, 0.00000000),
real2(0.00390625, 0.50000000),
real2(0.00781250, 0.25000000),
real2(0.01171875, 0.75000000),
real2(0.01562500, 0.12500000),
real2(0.01953125, 0.62500000),
real2(0.02343750, 0.37500000),
real2(0.02734375, 0.87500000),
real2(0.03125000, 0.06250000),
real2(0.03515625, 0.56250000),
real2(0.03906250, 0.31250000),
real2(0.04296875, 0.81250000),
real2(0.04687500, 0.18750000),
real2(0.05078125, 0.68750000),
real2(0.05468750, 0.43750000),
real2(0.05859375, 0.93750000),
real2(0.06250000, 0.03125000),
real2(0.06640625, 0.53125000),
real2(0.07031250, 0.28125000),
real2(0.07421875, 0.78125000),
real2(0.07812500, 0.15625000),
real2(0.08203125, 0.65625000),
real2(0.08593750, 0.40625000),
real2(0.08984375, 0.90625000),
real2(0.09375000, 0.09375000),
real2(0.09765625, 0.59375000),
real2(0.10156250, 0.34375000),
real2(0.10546875, 0.84375000),
real2(0.10937500, 0.21875000),
real2(0.11328125, 0.71875000),
real2(0.11718750, 0.46875000),
real2(0.12109375, 0.96875000),
real2(0.12500000, 0.01562500),
real2(0.12890625, 0.51562500),
real2(0.13281250, 0.26562500),
real2(0.13671875, 0.76562500),
real2(0.14062500, 0.14062500),
real2(0.14453125, 0.64062500),
real2(0.14843750, 0.39062500),
real2(0.15234375, 0.89062500),
real2(0.15625000, 0.07812500),
real2(0.16015625, 0.57812500),
real2(0.16406250, 0.32812500),
real2(0.16796875, 0.82812500),
real2(0.17187500, 0.20312500),
real2(0.17578125, 0.70312500),
real2(0.17968750, 0.45312500),
real2(0.18359375, 0.95312500),
real2(0.18750000, 0.04687500),
real2(0.19140625, 0.54687500),
real2(0.19531250, 0.29687500),
real2(0.19921875, 0.79687500),
real2(0.20312500, 0.17187500),
real2(0.20703125, 0.67187500),
real2(0.21093750, 0.42187500),
real2(0.21484375, 0.92187500),
real2(0.21875000, 0.10937500),
real2(0.22265625, 0.60937500),
real2(0.22656250, 0.35937500),
real2(0.23046875, 0.85937500),
real2(0.23437500, 0.23437500),
real2(0.23828125, 0.73437500),
real2(0.24218750, 0.48437500),
real2(0.24609375, 0.98437500),
real2(0.25000000, 0.00781250),
real2(0.25390625, 0.50781250),
real2(0.25781250, 0.25781250),
real2(0.26171875, 0.75781250),
real2(0.26562500, 0.13281250),
real2(0.26953125, 0.63281250),
real2(0.27343750, 0.38281250),
real2(0.27734375, 0.88281250),
real2(0.28125000, 0.07031250),
real2(0.28515625, 0.57031250),
real2(0.28906250, 0.32031250),
real2(0.29296875, 0.82031250),
real2(0.29687500, 0.19531250),
real2(0.30078125, 0.69531250),
real2(0.30468750, 0.44531250),
real2(0.30859375, 0.94531250),
real2(0.31250000, 0.03906250),
real2(0.31640625, 0.53906250),
real2(0.32031250, 0.28906250),
real2(0.32421875, 0.78906250),
real2(0.32812500, 0.16406250),
real2(0.33203125, 0.66406250),
real2(0.33593750, 0.41406250),
real2(0.33984375, 0.91406250),
real2(0.34375000, 0.10156250),
real2(0.34765625, 0.60156250),
real2(0.35156250, 0.35156250),
real2(0.35546875, 0.85156250),
real2(0.35937500, 0.22656250),
real2(0.36328125, 0.72656250),
real2(0.36718750, 0.47656250),
real2(0.37109375, 0.97656250),
real2(0.37500000, 0.02343750),
real2(0.37890625, 0.52343750),
real2(0.38281250, 0.27343750),
real2(0.38671875, 0.77343750),
real2(0.39062500, 0.14843750),
real2(0.39453125, 0.64843750),
real2(0.39843750, 0.39843750),
real2(0.40234375, 0.89843750),
real2(0.40625000, 0.08593750),
real2(0.41015625, 0.58593750),
real2(0.41406250, 0.33593750),
real2(0.41796875, 0.83593750),
real2(0.42187500, 0.21093750),
real2(0.42578125, 0.71093750),
real2(0.42968750, 0.46093750),
real2(0.43359375, 0.96093750),
real2(0.43750000, 0.05468750),
real2(0.44140625, 0.55468750),
real2(0.44531250, 0.30468750),
real2(0.44921875, 0.80468750),
real2(0.45312500, 0.17968750),
real2(0.45703125, 0.67968750),
real2(0.46093750, 0.42968750),
real2(0.46484375, 0.92968750),
real2(0.46875000, 0.11718750),
real2(0.47265625, 0.61718750),
real2(0.47656250, 0.36718750),
real2(0.48046875, 0.86718750),
real2(0.48437500, 0.24218750),
real2(0.48828125, 0.74218750),
real2(0.49218750, 0.49218750),
real2(0.49609375, 0.99218750),
real2(0.50000000, 0.00390625),
real2(0.50390625, 0.50390625),
real2(0.50781250, 0.25390625),
real2(0.51171875, 0.75390625),
real2(0.51562500, 0.12890625),
real2(0.51953125, 0.62890625),
real2(0.52343750, 0.37890625),
real2(0.52734375, 0.87890625),
real2(0.53125000, 0.06640625),
real2(0.53515625, 0.56640625),
real2(0.53906250, 0.31640625),
real2(0.54296875, 0.81640625),
real2(0.54687500, 0.19140625),
real2(0.55078125, 0.69140625),
real2(0.55468750, 0.44140625),
real2(0.55859375, 0.94140625),
real2(0.56250000, 0.03515625),
real2(0.56640625, 0.53515625),
real2(0.57031250, 0.28515625),
real2(0.57421875, 0.78515625),
real2(0.57812500, 0.16015625),
real2(0.58203125, 0.66015625),
real2(0.58593750, 0.41015625),
real2(0.58984375, 0.91015625),
real2(0.59375000, 0.09765625),
real2(0.59765625, 0.59765625),
real2(0.60156250, 0.34765625),
real2(0.60546875, 0.84765625),
real2(0.60937500, 0.22265625),
real2(0.61328125, 0.72265625),
real2(0.61718750, 0.47265625),
real2(0.62109375, 0.97265625),
real2(0.62500000, 0.01953125),
real2(0.62890625, 0.51953125),
real2(0.63281250, 0.26953125),
real2(0.63671875, 0.76953125),
real2(0.64062500, 0.14453125),
real2(0.64453125, 0.64453125),
real2(0.64843750, 0.39453125),
real2(0.65234375, 0.89453125),
real2(0.65625000, 0.08203125),
real2(0.66015625, 0.58203125),
real2(0.66406250, 0.33203125),
real2(0.66796875, 0.83203125),
real2(0.67187500, 0.20703125),
real2(0.67578125, 0.70703125),
real2(0.67968750, 0.45703125),
real2(0.68359375, 0.95703125),
real2(0.68750000, 0.05078125),
real2(0.69140625, 0.55078125),
real2(0.69531250, 0.30078125),
real2(0.69921875, 0.80078125),
real2(0.70312500, 0.17578125),
real2(0.70703125, 0.67578125),
real2(0.71093750, 0.42578125),
real2(0.71484375, 0.92578125),
real2(0.71875000, 0.11328125),
real2(0.72265625, 0.61328125),
real2(0.72656250, 0.36328125),
real2(0.73046875, 0.86328125),
real2(0.73437500, 0.23828125),
real2(0.73828125, 0.73828125),
real2(0.74218750, 0.48828125),
real2(0.74609375, 0.98828125),
real2(0.75000000, 0.01171875),
real2(0.75390625, 0.51171875),
real2(0.75781250, 0.26171875),
real2(0.76171875, 0.76171875),
real2(0.76562500, 0.13671875),
real2(0.76953125, 0.63671875),
real2(0.77343750, 0.38671875),
real2(0.77734375, 0.88671875),
real2(0.78125000, 0.07421875),
real2(0.78515625, 0.57421875),
real2(0.78906250, 0.32421875),
real2(0.79296875, 0.82421875),
real2(0.79687500, 0.19921875),
real2(0.80078125, 0.69921875),
real2(0.80468750, 0.44921875),
real2(0.80859375, 0.94921875),
real2(0.81250000, 0.04296875),
real2(0.81640625, 0.54296875),
real2(0.82031250, 0.29296875),
real2(0.82421875, 0.79296875),
real2(0.82812500, 0.16796875),
real2(0.83203125, 0.66796875),
real2(0.83593750, 0.41796875),
real2(0.83984375, 0.91796875),
real2(0.84375000, 0.10546875),
real2(0.84765625, 0.60546875),
real2(0.85156250, 0.35546875),
real2(0.85546875, 0.85546875),
real2(0.85937500, 0.23046875),
real2(0.86328125, 0.73046875),
real2(0.86718750, 0.48046875),
real2(0.87109375, 0.98046875),
real2(0.87500000, 0.02734375),
real2(0.87890625, 0.52734375),
real2(0.88281250, 0.27734375),
real2(0.88671875, 0.77734375),
real2(0.89062500, 0.15234375),
real2(0.89453125, 0.65234375),
real2(0.89843750, 0.40234375),
real2(0.90234375, 0.90234375),
real2(0.90625000, 0.08984375),
real2(0.91015625, 0.58984375),
real2(0.91406250, 0.33984375),
real2(0.91796875, 0.83984375),
real2(0.92187500, 0.21484375),
real2(0.92578125, 0.71484375),
real2(0.92968750, 0.46484375),
real2(0.93359375, 0.96484375),
real2(0.93750000, 0.05859375),
real2(0.94140625, 0.55859375),
real2(0.94531250, 0.30859375),
real2(0.94921875, 0.80859375),
real2(0.95312500, 0.18359375),
real2(0.95703125, 0.68359375),
real2(0.96093750, 0.43359375),
real2(0.96484375, 0.93359375),
real2(0.96875000, 0.12109375),
real2(0.97265625, 0.62109375),
real2(0.97656250, 0.37109375),
real2(0.98046875, 0.87109375),
real2(0.98437500, 0.24609375),
real2(0.98828125, 0.74609375),
real2(0.99218750, 0.49609375),
real2(0.99609375, 0.99609375)
};
// Loads elements from one of the precomputed tables for sample counts of 16, 32, 64, 256.
// Computes sample positions at runtime otherwise.
real2 Hammersley2d(uint i, uint sampleCount)
{
switch (sampleCount)
{
case 16: return k_Hammersley2dSeq16[i];
case 32: return k_Hammersley2dSeq32[i];
case 64: return k_Hammersley2dSeq64[i];
case 256: return k_Hammersley2dSeq256[i];
default: return Hammersley2dSeq(i, sampleCount);
}
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_HAMMERSLEY_INCLUDED

View File

@@ -0,0 +1,75 @@
// This structure abstract uv mapping inside one struct.
// It represent a mapping of any uv (with its associated tangent space for derivative if SurfaceGradient mode) - UVSet0 to 4, planar, triplanar
#ifndef __SAMPLEUVMAPPING_HLSL__
#define __SAMPLEUVMAPPING_HLSL__
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl"
#define UV_MAPPING_UVSET 0
#define UV_MAPPING_PLANAR 1
#define UV_MAPPING_TRIPLANAR 2
struct UVMapping
{
int mappingType;
float2 uv; // Current uv or planar uv
// Triplanar specific
float2 uvZY;
float2 uvXZ;
float2 uvXY;
float3 normalWS; // vertex normal
float3 triplanarWeights;
#ifdef SURFACE_GRADIENT
// tangent basis to use when mappingType is UV_MAPPING_UVSET
// these are vertex level in world space
float3 tangentWS;
float3 bitangentWS;
// TODO: store also object normal map for object triplanar
#endif
};
// Multiple includes of the file to handle all variations of textures sampling for regular, lod and bias
// Regular sampling functions
#define ADD_FUNC_SUFFIX(Name) Name
#define SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping, unused) SAMPLE_TEXTURE2D(textureName, samplerName, uvMapping)
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMappingInternal.hlsl"
#undef ADD_FUNC_SUFFIX
#undef SAMPLE_TEXTURE_FUNC
// Lod sampling functions
#define ADD_FUNC_SUFFIX(Name) MERGE_NAME(Name, Lod)
#define SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, uvMapping, lod)
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMappingInternal.hlsl"
#undef ADD_FUNC_SUFFIX
#undef SAMPLE_TEXTURE_FUNC
// Bias sampling functions
#define ADD_FUNC_SUFFIX(Name) MERGE_NAME(Name, Bias)
#define SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping, bias) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, uvMapping, bias)
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMappingInternal.hlsl"
#undef ADD_FUNC_SUFFIX
#undef SAMPLE_TEXTURE_FUNC
// Macro to improve readibility of surface data
#define SAMPLE_UVMAPPING_TEXTURE2D(textureName, samplerName, uvMapping) SampleUVMapping(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, 0.0) // Last 0.0 is unused
#define SAMPLE_UVMAPPING_TEXTURE2D_LOD(textureName, samplerName, uvMapping, lod) SampleUVMappingLod(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, lod)
#define SAMPLE_UVMAPPING_TEXTURE2D_BIAS(textureName, samplerName, uvMapping, bias) SampleUVMappingBias(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, bias)
#define SAMPLE_UVMAPPING_NORMALMAP(textureName, samplerName, uvMapping, scale) SampleUVMappingNormal(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, 0.0)
#define SAMPLE_UVMAPPING_NORMALMAP_LOD(textureName, samplerName, uvMapping, scale, lod) SampleUVMappingNormalLod(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, lod)
#define SAMPLE_UVMAPPING_NORMALMAP_BIAS(textureName, samplerName, uvMapping, scale, bias) SampleUVMappingNormalBias(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, bias)
#define SAMPLE_UVMAPPING_NORMALMAP_AG(textureName, samplerName, uvMapping, scale) SampleUVMappingNormalAG(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, 0.0)
#define SAMPLE_UVMAPPING_NORMALMAP_AG_LOD(textureName, samplerName, uvMapping, scale, lod) SampleUVMappingNormalAGLod(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, lod)
#define SAMPLE_UVMAPPING_NORMALMAP_AG_BIAS(textureName, samplerName, uvMapping, scale, bias) SampleUVMappingNormalAGBias(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, bias)
#define SAMPLE_UVMAPPING_NORMALMAP_RGB(textureName, samplerName, uvMapping, scale) SampleUVMappingNormalRGB(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, 0.0)
#define SAMPLE_UVMAPPING_NORMALMAP_RGB_LOD(textureName, samplerName, uvMapping, scale, lod) SampleUVMappingNormalRGBLod(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, lod)
#define SAMPLE_UVMAPPING_NORMALMAP_RGB_BIAS(textureName, samplerName, uvMapping, scale, bias) SampleUVMappingNormalRGBBias(TEXTURE2D_ARGS(textureName, samplerName), uvMapping, scale, bias)
#endif //__SAMPLEUVMAPPING_HLSL__

View File

@@ -0,0 +1,64 @@
// These functions are use to hide the handling of triplanar mapping
// Normal need a specific treatment as they use special encoding for both base and detail map
// Also we use multiple inclusion to handle the various variation for lod and bias
// param can be unused, lod or bias
real4 ADD_FUNC_SUFFIX(SampleUVMapping)(TEXTURE2D_PARAM(textureName, samplerName), UVMapping uvMapping, real param)
{
if (uvMapping.mappingType == UV_MAPPING_TRIPLANAR)
{
real3 triplanarWeights = uvMapping.triplanarWeights;
real4 val = real4(0.0, 0.0, 0.0, 0.0);
if (triplanarWeights.x > 0.0)
val += triplanarWeights.x * SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvZY, param);
if (triplanarWeights.y > 0.0)
val += triplanarWeights.y * SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvXZ, param);
if (triplanarWeights.z > 0.0)
val += triplanarWeights.z * SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvXY, param);
return val;
}
else // UV_MAPPING_UVSET / UV_MAPPING_PLANAR
{
return SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uv, param);
}
}
// Nested multiple includes of the file to handle all variations of normal map (AG, RG or RGB)
// This version is use for the base normal map (BC5 or DXT5nm)
#define ADD_NORMAL_FUNC_SUFFIX(Name) Name
#if defined(UNITY_ASTC_NORMALMAP_ENCODING)
#define UNPACK_NORMAL_FUNC UnpackNormalAG
#define UNPACK_DERIVATIVE_FUNC UnpackDerivativeNormalAG
#elif defined(UNITY_NO_DXT5nm)
#define UNPACK_NORMAL_FUNC UnpackNormalRGB
#define UNPACK_DERIVATIVE_FUNC UnpackDerivativeNormalRGB
#else
#define UNPACK_NORMAL_FUNC UnpackNormalmapRGorAG
#define UNPACK_DERIVATIVE_FUNC UnpackDerivativeNormalRGorAG
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl"
#undef ADD_NORMAL_FUNC_SUFFIX
#undef UNPACK_NORMAL_FUNC
#undef UNPACK_DERIVATIVE_FUNC
// This version is for normalmap with AG encoding only. Use with details map encoded with others properties (like smoothness).
#define ADD_NORMAL_FUNC_SUFFIX(Name) MERGE_NAME(Name, AG)
#define UNPACK_NORMAL_FUNC UnpackNormalAG
#define UNPACK_DERIVATIVE_FUNC UnpackDerivativeNormalAG
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl"
#undef ADD_NORMAL_FUNC_SUFFIX
#undef UNPACK_NORMAL_FUNC
#undef UNPACK_DERIVATIVE_FUNC
// This version is for normalmap with RGB encoding only, i.e uncompress or BC7.
#define ADD_NORMAL_FUNC_SUFFIX(Name) MERGE_NAME(Name, RGB)
#define UNPACK_NORMAL_FUNC UnpackNormalRGB
#define UNPACK_DERIVATIVE_FUNC UnpackDerivativeNormalRGB
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl"
#undef ADD_NORMAL_FUNC_SUFFIX
#undef UNPACK_NORMAL_FUNC
#undef UNPACK_DERIVATIVE_FUNC

View File

@@ -0,0 +1,57 @@
real3 ADD_FUNC_SUFFIX(ADD_NORMAL_FUNC_SUFFIX(SampleUVMappingNormal))(TEXTURE2D_PARAM(textureName, samplerName), UVMapping uvMapping, real scale, real param)
{
if (uvMapping.mappingType == UV_MAPPING_TRIPLANAR)
{
real3 triplanarWeights = uvMapping.triplanarWeights;
#ifdef SURFACE_GRADIENT
// Height map gradient. Basically, it encodes height map slopes along S and T axes.
real2 derivXplane;
real2 derivYPlane;
real2 derivZPlane;
derivXplane = derivYPlane = derivZPlane = real2(0.0, 0.0);
if (triplanarWeights.x > 0.0)
derivXplane = triplanarWeights.x * UNPACK_DERIVATIVE_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvZY, param), scale);
if (triplanarWeights.y > 0.0)
derivYPlane = triplanarWeights.y * UNPACK_DERIVATIVE_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvXZ, param), scale);
if (triplanarWeights.z > 0.0)
derivZPlane = triplanarWeights.z * UNPACK_DERIVATIVE_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvXY, param), scale);
// Assume derivXplane, derivYPlane and derivZPlane sampled using (z,y), (z,x) and (x,y) respectively.
// TODO: Check with morten convention! Do it follow ours ?
real3 volumeGrad = real3(derivZPlane.x + derivYPlane.x, derivZPlane.y + derivXplane.y, derivXplane.x + derivYPlane.y);
return SurfaceGradientFromVolumeGradient(uvMapping.normalWS, volumeGrad);
#else
real3 val = real3(0.0, 0.0, 0.0);
if (triplanarWeights.x > 0.0)
val += triplanarWeights.x * UNPACK_NORMAL_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvZY, param), scale);
if (triplanarWeights.y > 0.0)
val += triplanarWeights.y * UNPACK_NORMAL_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvXZ, param), scale);
if (triplanarWeights.z > 0.0)
val += triplanarWeights.z * UNPACK_NORMAL_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uvXY, param), scale);
return normalize(val);
#endif
}
#ifdef SURFACE_GRADIENT
else if (uvMapping.mappingType == UV_MAPPING_PLANAR)
{
// Note: Planar is on uv coordinate (and not uvXZ)
real2 derivYPlane = UNPACK_DERIVATIVE_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uv, param), scale);
// See comment above
real3 volumeGrad = real3(derivYPlane.x, 0.0, derivYPlane.y);
return SurfaceGradientFromVolumeGradient(uvMapping.normalWS, volumeGrad);
}
#endif
else
{
#ifdef SURFACE_GRADIENT
real2 deriv = UNPACK_DERIVATIVE_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uv, param), scale);
return SurfaceGradientFromTBN(deriv, uvMapping.tangentWS, uvMapping.bitangentWS);
#else
return UNPACK_NORMAL_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uv, param), scale);
#endif
}
}

View File

@@ -0,0 +1,316 @@
#ifndef UNITY_SAMPLING_INCLUDED
#define UNITY_SAMPLING_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
//-----------------------------------------------------------------------------
// Sample generator
//-----------------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Fibonacci.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Hammersley.hlsl"
//-----------------------------------------------------------------------------
// Coordinate system conversion
//-----------------------------------------------------------------------------
// Transforms the unit vector from the spherical to the Cartesian (right-handed, Z up) coordinate.
real3 SphericalToCartesian(real cosPhi, real sinPhi, real cosTheta)
{
real sinTheta = SinFromCos(cosTheta);
return real3(real2(cosPhi, sinPhi) * sinTheta, cosTheta);
}
real3 SphericalToCartesian(real phi, real cosTheta)
{
real sinPhi, cosPhi;
sincos(phi, sinPhi, cosPhi);
return SphericalToCartesian(cosPhi, sinPhi, cosTheta);
}
// Converts Cartesian coordinates given in the right-handed coordinate system
// with Z pointing upwards (OpenGL style) to the coordinates in the left-handed
// coordinate system with Y pointing up and Z facing forward (DirectX style).
real3 TransformGLtoDX(real3 v)
{
return v.xzy;
}
// Performs conversion from equiareal map coordinates to Cartesian (DirectX cubemap) ones.
real3 ConvertEquiarealToCubemap(real u, real v)
{
real phi = TWO_PI - TWO_PI * u;
real cosTheta = 1.0 - 2.0 * v;
return TransformGLtoDX(SphericalToCartesian(phi, cosTheta));
}
// Convert a texel position into normalized position [-1..1]x[-1..1]
real2 CubemapTexelToNVC(uint2 unPositionTXS, uint cubemapSize)
{
return 2.0 * real2(unPositionTXS) / real(max(cubemapSize - 1, 1)) - 1.0;
}
// Map cubemap face to world vector basis
static const real3 CUBEMAP_FACE_BASIS_MAPPING[6][3] =
{
//XPOS face
{
real3(0.0, 0.0, -1.0),
real3(0.0, -1.0, 0.0),
real3(1.0, 0.0, 0.0)
},
//XNEG face
{
real3(0.0, 0.0, 1.0),
real3(0.0, -1.0, 0.0),
real3(-1.0, 0.0, 0.0)
},
//YPOS face
{
real3(1.0, 0.0, 0.0),
real3(0.0, 0.0, 1.0),
real3(0.0, 1.0, 0.0)
},
//YNEG face
{
real3(1.0, 0.0, 0.0),
real3(0.0, 0.0, -1.0),
real3(0.0, -1.0, 0.0)
},
//ZPOS face
{
real3(1.0, 0.0, 0.0),
real3(0.0, -1.0, 0.0),
real3(0.0, 0.0, 1.0)
},
//ZNEG face
{
real3(-1.0, 0.0, 0.0),
real3(0.0, -1.0, 0.0),
real3(0.0, 0.0, -1.0)
}
};
// Convert a normalized cubemap face position into a direction
real3 CubemapTexelToDirection(real2 positionNVC, uint faceId)
{
real3 dir = CUBEMAP_FACE_BASIS_MAPPING[faceId][0] * positionNVC.x
+ CUBEMAP_FACE_BASIS_MAPPING[faceId][1] * positionNVC.y
+ CUBEMAP_FACE_BASIS_MAPPING[faceId][2];
return normalize(dir);
}
//-----------------------------------------------------------------------------
// Sampling function
// Reference : http://www.cs.virginia.edu/~jdl/bib/globillum/mis/shirley96.pdf + PBRT
//-----------------------------------------------------------------------------
// Performs uniform sampling of the unit disk.
// Ref: PBRT v3, p. 777.
real2 SampleDiskUniform(real u1, real u2)
{
real r = sqrt(u1);
real phi = TWO_PI * u2;
real sinPhi, cosPhi;
sincos(phi, sinPhi, cosPhi);
return r * real2(cosPhi, sinPhi);
}
// Performs cubic sampling of the unit disk.
real2 SampleDiskCubic(real u1, real u2)
{
real r = u1;
real phi = TWO_PI * u2;
real sinPhi, cosPhi;
sincos(phi, sinPhi, cosPhi);
return r * real2(cosPhi, sinPhi);
}
real3 SampleConeUniform(real u1, real u2, real cos_theta)
{
float r0 = cos_theta + u1 * (1.0f - cos_theta);
float r = sqrt(max(0.0, 1.0 - r0 * r0));
float phi = TWO_PI * u2;
return float3(r * cos(phi), r * sin(phi), r0);
}
real3 SampleSphereUniform(real u1, real u2)
{
real phi = TWO_PI * u2;
real cosTheta = 1.0 - 2.0 * u1;
return SphericalToCartesian(phi, cosTheta);
}
// Performs cosine-weighted sampling of the hemisphere.
// Ref: PBRT v3, p. 780.
real3 SampleHemisphereCosine(real u1, real u2)
{
real3 localL;
// Since we don't really care about the area distortion,
// we substitute uniform disk sampling for the concentric one.
localL.xy = SampleDiskUniform(u1, u2);
// Project the point from the disk onto the hemisphere.
localL.z = sqrt(1.0 - u1);
return localL;
}
// Cosine-weighted sampling without the tangent frame.
// Ref: http://www.amietia.com/lambertnotangent.html
real3 SampleHemisphereCosine(real u1, real u2, real3 normal)
{
// This function needs to used safenormalize because there is a probability
// that the generated direction is the exact opposite of the normal and that would lead
// to a nan vector otheriwse.
real3 pointOnSphere = SampleSphereUniform(u1, u2);
return SafeNormalize(normal + pointOnSphere);
}
real3 SampleHemisphereUniform(real u1, real u2)
{
real phi = TWO_PI * u2;
real cosTheta = 1.0 - u1;
return SphericalToCartesian(phi, cosTheta);
}
void SampleSphere(real2 u,
real4x4 localToWorld,
real radius,
out real lightPdf,
out real3 P,
out real3 Ns)
{
real u1 = u.x;
real u2 = u.y;
Ns = SampleSphereUniform(u1, u2);
// Transform from unit sphere to world space
P = radius * Ns + localToWorld[3].xyz;
// pdf is inverse of area
lightPdf = 1.0 / (FOUR_PI * radius * radius);
}
void SampleHemisphere(real2 u,
real4x4 localToWorld,
real radius,
out real lightPdf,
out real3 P,
out real3 Ns)
{
real u1 = u.x;
real u2 = u.y;
// Random point at hemisphere surface
Ns = -SampleHemisphereUniform(u1, u2); // We want the y down hemisphere
P = radius * Ns;
// Transform to world space
P = mul(real4(P, 1.0), localToWorld).xyz;
Ns = mul(Ns, (real3x3)(localToWorld));
// pdf is inverse of area
lightPdf = 1.0 / (TWO_PI * radius * radius);
}
// Note: The cylinder has no end caps (i.e. no disk on the side)
void SampleCylinder(real2 u,
real4x4 localToWorld,
real radius,
real width,
out real lightPdf,
out real3 P,
out real3 Ns)
{
real u1 = u.x;
real u2 = u.y;
// Random point at cylinder surface
real t = (u1 - 0.5) * width;
real theta = 2.0 * PI * u2;
real cosTheta = cos(theta);
real sinTheta = sin(theta);
// Cylinder are align on the right axis
P = real3(t, radius * cosTheta, radius * sinTheta);
Ns = normalize(real3(0.0, cosTheta, sinTheta));
// Transform to world space
P = mul(real4(P, 1.0), localToWorld).xyz;
Ns = mul(Ns, (real3x3)(localToWorld));
// pdf is inverse of area
lightPdf = 1.0 / (TWO_PI * radius * width);
}
void SampleRectangle(real2 u,
real4x4 localToWorld,
real width,
real height,
out real lightPdf,
out real3 P,
out real3 Ns)
{
// Random point at rectangle surface
P = real3((u.x - 0.5) * width, (u.y - 0.5) * height, 0);
Ns = real3(0, 0, -1); // Light down (-Z)
// Transform to world space
P = mul(real4(P, 1.0), localToWorld).xyz;
Ns = mul(Ns, (real3x3)(localToWorld));
// pdf is inverse of area
lightPdf = 1.0 / (width * height);
}
void SampleDisk(real2 u,
real4x4 localToWorld,
real radius,
out real lightPdf,
out real3 P,
out real3 Ns)
{
// Random point at disk surface
P = real3(radius * SampleDiskUniform(u.x, u.y), 0);
Ns = real3(0.0, 0.0, -1.0); // Light down (-Z)
// Transform to world space
P = mul(real4(P, 1.0), localToWorld).xyz;
Ns = mul(Ns, (real3x3)(localToWorld));
// pdf is inverse of area
lightPdf = 1.0 / (PI * radius * radius);
}
// Solid angle cone sampling.
// Takes the cosine of the aperture as an input.
void SampleCone(real2 u, real cosHalfAngle,
out real3 dir, out real rcpPdf)
{
real cosTheta = lerp(1, cosHalfAngle, u.x);
real phi = TWO_PI * u.y;
dir = SphericalToCartesian(phi, cosTheta);
rcpPdf = TWO_PI * (1 - cosHalfAngle);
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif // UNITY_SAMPLING_INCLUDED

View File

@@ -0,0 +1,247 @@
#ifndef SHADOW_SAMPLING_TENT_INCLUDED
#define SHADOW_SAMPLING_TENT_INCLUDED
// ------------------------------------------------------------------
// PCF Filtering Tent Functions
// ------------------------------------------------------------------
// Assuming a isoceles right angled triangle of height "triangleHeight" (as drawn below).
// This function return the area of the triangle above the first texel.
//
// |\ <-- 45 degree slop isosceles right angled triangle
// | \
// ---- <-- length of this side is "triangleHeight"
// _ _ _ _ <-- texels
real SampleShadow_GetTriangleTexelArea(real triangleHeight)
{
return triangleHeight - 0.5;
}
// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
// This function return the area of the triangle above each of those texels.
// | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center
// / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)
// / \
// _ _ _ _ <-- texels
// X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)
void SampleShadow_GetTexelAreas_Tent_3x3(real offset, out real4 computedArea, out real4 computedAreaUncut)
{
// Compute the exterior areas
real offset01SquaredHalved = (offset + 0.5) * (offset + 0.5) * 0.5;
computedAreaUncut.x = computedArea.x = offset01SquaredHalved - offset;
computedAreaUncut.w = computedArea.w = offset01SquaredHalved;
// Compute the middle areas
// For Y : We find the area in Y of as if the left section of the isoceles triangle would
// intersect the axis between Y and Z (ie where offset = 0).
computedAreaUncut.y = SampleShadow_GetTriangleTexelArea(1.5 - offset);
// This area is superior to the one we are looking for if (offset < 0) thus we need to
// subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).
real clampedOffsetLeft = min(offset,0);
real areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;
computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;
// We do the same for the Z but with the right part of the isoceles triangle
computedAreaUncut.z = SampleShadow_GetTriangleTexelArea(1.5 + offset);
real clampedOffsetRight = max(offset,0);
real areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;
computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;
}
// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
// This function return the weight of each texels area relative to the full triangle area.
void SampleShadow_GetTexelWeights_Tent_3x3(real offset, out real4 computedWeight)
{
real4 dummy;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedWeight, dummy);
computedWeight *= 0.44444;//0.44 == 1/(the triangle area)
}
// Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.
// This function return the weight of each texels area relative to the full triangle area.
// / \
// _ _ _ _ _ _ <-- texels
// 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])
void SampleShadow_GetTexelWeights_Tent_5x5(real offset, out real3 texelsWeightsA, out real3 texelsWeightsB)
{
// See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
real4 computedArea_From3texelTriangle;
real4 computedAreaUncut_From3texelTriangle;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
// Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
// the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.
// 0.16 is 1/(the triangle area)
texelsWeightsA.x = 0.16 * (computedArea_From3texelTriangle.x);
texelsWeightsA.y = 0.16 * (computedAreaUncut_From3texelTriangle.y);
texelsWeightsA.z = 0.16 * (computedArea_From3texelTriangle.y + 1);
texelsWeightsB.x = 0.16 * (computedArea_From3texelTriangle.z + 1);
texelsWeightsB.y = 0.16 * (computedAreaUncut_From3texelTriangle.z);
texelsWeightsB.z = 0.16 * (computedArea_From3texelTriangle.w);
}
// Assuming a isoceles triangle of 3.5 texel height and 7 texels wide lying on 8 texels.
// This function return the weight of each texels area relative to the full triangle area.
// / \
// _ _ _ _ _ _ _ _ <-- texels
// 0 1 2 3 4 5 6 7 <-- computed area indices (in texelsWeights[])
void SampleShadow_GetTexelWeights_Tent_7x7(real offset, out real4 texelsWeightsA, out real4 texelsWeightsB)
{
// See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
real4 computedArea_From3texelTriangle;
real4 computedAreaUncut_From3texelTriangle;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
// Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
// the 7 texel wide triangle can be seen as the 3 texel wide one but shifted up by two unit/texel.
// 0.081632 is 1/(the triangle area)
texelsWeightsA.x = 0.081632 * (computedArea_From3texelTriangle.x);
texelsWeightsA.y = 0.081632 * (computedAreaUncut_From3texelTriangle.y);
texelsWeightsA.z = 0.081632 * (computedAreaUncut_From3texelTriangle.y + 1);
texelsWeightsA.w = 0.081632 * (computedArea_From3texelTriangle.y + 2);
texelsWeightsB.x = 0.081632 * (computedArea_From3texelTriangle.z + 2);
texelsWeightsB.y = 0.081632 * (computedAreaUncut_From3texelTriangle.z + 1);
texelsWeightsB.z = 0.081632 * (computedAreaUncut_From3texelTriangle.z);
texelsWeightsB.w = 0.081632 * (computedArea_From3texelTriangle.w);
}
// 3x3 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_3x3(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[4], out real2 fetchesUV[4])
{
// tent base is 3x3 base thus covering from 9 to 12 texels, thus we need 4 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based
real4 texelsWeightsU, texelsWeightsV;
SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU);
SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real2 fetchesWeightsU = texelsWeightsU.xz + texelsWeightsU.yw;
real2 fetchesWeightsV = texelsWeightsV.xz + texelsWeightsV.yw;
// move the PCF bilinear fetches to respect texels weights
real2 fetchesOffsetsU = texelsWeightsU.yw / fetchesWeightsU.xy + real2(-1.5,0.5);
real2 fetchesOffsetsV = texelsWeightsV.yw / fetchesWeightsV.xy + real2(-1.5,0.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[3] = fetchesWeightsU.y * fetchesWeightsV.y;
}
// 5x5 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_5x5(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[9], out real2 fetchesUV[9])
{
// tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
real3 texelsWeightsU_A, texelsWeightsU_B;
real3 texelsWeightsV_A, texelsWeightsV_B;
SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real3 fetchesWeightsU = real3(texelsWeightsU_A.xz, texelsWeightsU_B.y) + real3(texelsWeightsU_A.y, texelsWeightsU_B.xz);
real3 fetchesWeightsV = real3(texelsWeightsV_A.xz, texelsWeightsV_B.y) + real3(texelsWeightsV_A.y, texelsWeightsV_B.xz);
// move the PCF bilinear fetches to respect texels weights
real3 fetchesOffsetsU = real3(texelsWeightsU_A.y, texelsWeightsU_B.xz) / fetchesWeightsU.xyz + real3(-2.5,-0.5,1.5);
real3 fetchesOffsetsV = real3(texelsWeightsV_A.y, texelsWeightsV_B.xz) / fetchesWeightsV.xyz + real3(-2.5,-0.5,1.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xxx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yyy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y;
fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y;
fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z;
fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z;
fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z;
}
// 7x7 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_7x7(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[16], out real2 fetchesUV[16])
{
// tent base is 7x7 base thus covering from 49 to 64 texels, thus we need 16 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
real4 texelsWeightsU_A, texelsWeightsU_B;
real4 texelsWeightsV_A, texelsWeightsV_B;
SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real4 fetchesWeightsU = real4(texelsWeightsU_A.xz, texelsWeightsU_B.xz) + real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw);
real4 fetchesWeightsV = real4(texelsWeightsV_A.xz, texelsWeightsV_B.xz) + real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw);
// move the PCF bilinear fetches to respect texels weights
real4 fetchesOffsetsU = real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw) / fetchesWeightsU.xyzw + real4(-3.5,-1.5,0.5,2.5);
real4 fetchesOffsetsV = real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw) / fetchesWeightsV.xyzw + real4(-3.5,-1.5,0.5,2.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xxxx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yyyy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.x);
fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.y);
fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
fetchesUV[9] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
fetchesUV[10] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
fetchesUV[11] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.z);
fetchesUV[12] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.w);
fetchesUV[13] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.w);
fetchesUV[14] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.w);
fetchesUV[15] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.w);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
fetchesWeights[3] = fetchesWeightsU.w * fetchesWeightsV.x;
fetchesWeights[4] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[5] = fetchesWeightsU.y * fetchesWeightsV.y;
fetchesWeights[6] = fetchesWeightsU.z * fetchesWeightsV.y;
fetchesWeights[7] = fetchesWeightsU.w * fetchesWeightsV.y;
fetchesWeights[8] = fetchesWeightsU.x * fetchesWeightsV.z;
fetchesWeights[9] = fetchesWeightsU.y * fetchesWeightsV.z;
fetchesWeights[10] = fetchesWeightsU.z * fetchesWeightsV.z;
fetchesWeights[11] = fetchesWeightsU.w * fetchesWeightsV.z;
fetchesWeights[12] = fetchesWeightsU.x * fetchesWeightsV.w;
fetchesWeights[13] = fetchesWeightsU.y * fetchesWeightsV.w;
fetchesWeights[14] = fetchesWeightsU.z * fetchesWeightsV.w;
fetchesWeights[15] = fetchesWeightsU.w * fetchesWeightsV.w;
}
#endif

View File

@@ -0,0 +1,82 @@
#ifndef UNITY_SPACE_FILLING_CURVES_INCLUDED
#define UNITY_SPACE_FILLING_CURVES_INCLUDED
// "Insert" a 0 bit after each of the 16 low bits of x.
// Ref: https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
uint Part1By1(uint x)
{
x &= 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210
x = (x ^ (x << 8)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210
x = (x ^ (x << 4)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210
x = (x ^ (x << 2)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10
x = (x ^ (x << 1)) & 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
return x;
}
// "Insert" two 0 bits after each of the 10 low bits of x.
// Ref: https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
uint Part1By2(uint x)
{
x &= 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210
x = (x ^ (x << 16)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210
x = (x ^ (x << 8)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210
x = (x ^ (x << 4)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10
x = (x ^ (x << 2)) & 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
return x;
}
// Inverse of Part1By1 - "delete" all odd-indexed bits.
// Ref: https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
uint Compact1By1(uint x)
{
x &= 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
x = (x ^ (x >> 1)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10
x = (x ^ (x >> 2)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210
x = (x ^ (x >> 4)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210
x = (x ^ (x >> 8)) & 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210
return x;
}
// Inverse of Part1By2 - "delete" all bits not at positions divisible by 3.
// Ref: https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
uint Compact1By2(uint x)
{
x &= 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
x = (x ^ (x >> 2)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10
x = (x ^ (x >> 4)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210
x = (x ^ (x >> 8)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210
x = (x ^ (x >> 16)) & 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210
return x;
}
uint EncodeMorton2D(uint2 coord)
{
return (Part1By1(coord.y) << 1) + Part1By1(coord.x);
}
uint EncodeMorton3D(uint3 coord)
{
return (Part1By2(coord.z) << 2) + (Part1By2(coord.y) << 1) + Part1By2(coord.x);
}
uint2 DecodeMorton2D(uint code)
{
return uint2(Compact1By1(code >> 0), Compact1By1(code >> 1));
}
uint3 DecodeMorton3D(uint code)
{
return uint3(Compact1By2(code >> 0), Compact1By2(code >> 1), Compact1By2(code >> 2));
}
uint InterleaveQuad(uint2 quad)
{
return quad.x + 2 * quad.y;
}
uint2 DeinterleaveQuad(uint code)
{
return uint2(code & 1, (code >> 1) & 1);
}
#endif // UNITY_SPACE_FILLING_CURVES_INCLUDED

View File

@@ -0,0 +1,247 @@
#ifndef UNITY_SPACE_TRANSFORMS_INCLUDED
#define UNITY_SPACE_TRANSFORMS_INCLUDED
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (disable : 3205) // conversion of larger type to smaller
#endif
// Caution: For HDRP, adding a function in this file requires adding the appropriate #define in PickingSpaceTransforms.hlsl
// Return the PreTranslated ObjectToWorld Matrix (i.e matrix with _WorldSpaceCameraPos apply to it if we use camera relative rendering)
float4x4 GetObjectToWorldMatrix()
{
return UNITY_MATRIX_M;
}
float4x4 GetWorldToObjectMatrix()
{
return UNITY_MATRIX_I_M;
}
float4x4 GetWorldToViewMatrix()
{
return UNITY_MATRIX_V;
}
// Transform to homogenous clip space
float4x4 GetWorldToHClipMatrix()
{
return UNITY_MATRIX_VP;
}
// Transform to homogenous clip space
float4x4 GetViewToHClipMatrix()
{
return UNITY_MATRIX_P;
}
// This function always return the absolute position in WS
float3 GetAbsolutePositionWS(float3 positionRWS)
{
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionRWS += _WorldSpaceCameraPos.xyz;
#endif
return positionRWS;
}
// This function return the camera relative position in WS
float3 GetCameraRelativePositionWS(float3 positionWS)
{
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS -= _WorldSpaceCameraPos.xyz;
#endif
return positionWS;
}
real GetOddNegativeScale()
{
// FIXME: We should be able to just return unity_WorldTransformParams.w, but it is not
// properly set at the moment, when doing ray-tracing; once this has been fixed in cpp,
// we can revert back to the former implementation.
return unity_WorldTransformParams.w >= 0.0 ? 1.0 : -1.0;
}
float3 TransformObjectToWorld(float3 positionOS)
{
#if defined(SHADER_STAGE_RAY_TRACING)
return mul(ObjectToWorld3x4(), float4(positionOS, 1.0)).xyz;
#else
return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz;
#endif
}
float3 TransformWorldToObject(float3 positionWS)
{
#if defined(SHADER_STAGE_RAY_TRACING)
return mul(WorldToObject3x4(), float4(positionWS, 1.0)).xyz;
#else
return mul(GetWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz;
#endif
}
float3 TransformWorldToView(float3 positionWS)
{
return mul(GetWorldToViewMatrix(), float4(positionWS, 1.0)).xyz;
}
// Transforms position from object space to homogenous space
float4 TransformObjectToHClip(float3 positionOS)
{
// More efficient than computing M*VP matrix product
return mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)));
}
// Tranforms position from world space to homogenous space
float4 TransformWorldToHClip(float3 positionWS)
{
return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0));
}
// Tranforms position from view space to homogenous space
float4 TransformWViewToHClip(float3 positionVS)
{
return mul(GetViewToHClipMatrix(), float4(positionVS, 1.0));
}
// Normalize to support uniform scaling
float3 TransformObjectToWorldDir(float3 dirOS, bool doNormalize = true)
{
#ifndef SHADER_STAGE_RAY_TRACING
float3 dirWS = mul((float3x3)GetObjectToWorldMatrix(), dirOS);
#else
float3 dirWS = mul((float3x3)ObjectToWorld3x4(), dirOS);
#endif
if (doNormalize)
return SafeNormalize(dirWS);
return dirWS;
}
// Normalize to support uniform scaling
float3 TransformWorldToObjectDir(float3 dirWS, bool doNormalize = true)
{
#ifndef SHADER_STAGE_RAY_TRACING
float3 dirOS = mul((float3x3)GetWorldToObjectMatrix(), dirWS);
#else
float3 dirOS = mul((float3x3)WorldToObject3x4(), dirWS);
#endif
if (doNormalize)
return normalize(dirOS);
return dirOS;
}
// Tranforms vector from world space to view space
real3 TransformWorldToViewDir(real3 dirWS, bool doNormalize = false)
{
float3 dirVS = mul((real3x3)GetWorldToViewMatrix(), dirWS).xyz;
if (doNormalize)
return normalize(dirVS);
return dirVS;
}
// Tranforms vector from world space to homogenous space
real3 TransformWorldToHClipDir(real3 directionWS, bool doNormalize = false)
{
float3 dirHCS = mul((real3x3)GetWorldToHClipMatrix(), directionWS).xyz;
if (doNormalize)
return normalize(dirHCS);
return dirHCS;
}
// Transforms normal from object to world space
float3 TransformObjectToWorldNormal(float3 normalOS, bool doNormalize = true)
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return TransformObjectToWorldDir(normalOS, doNormalize);
#else
// Normal need to be multiply by inverse transpose
float3 normalWS = mul(normalOS, (float3x3)GetWorldToObjectMatrix());
if (doNormalize)
return SafeNormalize(normalWS);
return normalWS;
#endif
}
// Transforms normal from world to object space
float3 TransformWorldToObjectNormal(float3 normalWS, bool doNormalize = true)
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return TransformWorldToObjectDir(normalWS, doNormalize);
#else
// Normal need to be multiply by inverse transpose
float3 normalOS = mul(normalWS, (float3x3)GetObjectToWorldMatrix());
if (doNormalize)
return SafeNormalize(normalOS);
return normalOS;
#endif
}
real3x3 CreateTangentToWorld(real3 normal, real3 tangent, real flipSign)
{
// For odd-negative scale transforms we need to flip the sign
real sgn = flipSign * GetOddNegativeScale();
real3 bitangent = cross(normal, tangent) * sgn;
return real3x3(tangent, bitangent, normal);
}
real3 TransformTangentToWorld(real3 dirTS, real3x3 tangentToWorld)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
return mul(dirTS, tangentToWorld);
}
// This function does the exact inverse of TransformTangentToWorld() and is
// also decribed within comments in mikktspace.h and it follows implicitly
// from the scalar triple product (google it).
real3 TransformWorldToTangent(real3 dirWS, real3x3 tangentToWorld)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
float3 row0 = tangentToWorld[0];
float3 row1 = tangentToWorld[1];
float3 row2 = tangentToWorld[2];
// these are the columns of the inverse matrix but scaled by the determinant
float3 col0 = cross(row1, row2);
float3 col1 = cross(row2, row0);
float3 col2 = cross(row0, row1);
float determinant = dot(row0, col0);
float sgn = determinant<0.0 ? (-1.0) : 1.0;
// inverse transposed but scaled by determinant
// Will remove transpose part by using matrix as the first arg in the mul() below
// this makes it the exact inverse of what TransformTangentToWorld() does.
real3x3 matTBN_I_T = real3x3(col0, col1, col2);
return SafeNormalize( sgn * mul(matTBN_I_T, dirWS) );
}
real3 TransformTangentToObject(real3 dirTS, real3x3 tangentToWorld)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
real3 normalWS = TransformTangentToWorld(dirTS, tangentToWorld);
return TransformWorldToObjectNormal(normalWS);
}
real3 TransformObjectToTangent(real3 dirOS, real3x3 tangentToWorld)
{
// Note matrix is in row major convention with left multiplication as it is build on the fly
// don't normalize, as normalWS will be normalized after TransformWorldToTangent
float3 normalWS = TransformObjectToWorldNormal(dirOS, false);
// transform from world to tangent
return TransformWorldToTangent(normalWS, tangentToWorld);
}
#if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
#pragma warning (enable : 3205) // conversion of larger type to smaller
#endif
#endif

View File

@@ -0,0 +1,66 @@
#define TESSELLATION_INTERPOLATE_BARY(name, bary) output.name = input0.name * bary.x + input1.name * bary.y + input2.name * bary.z
// p0, p1, p2 triangle world position
// p0, p1, p2 triangle world vertex normal
real3 PhongTessellation(real3 positionWS, real3 p0, real3 p1, real3 p2, real3 n0, real3 n1, real3 n2, real3 baryCoords, real shape)
{
real3 c0 = ProjectPointOnPlane(positionWS, p0, n0);
real3 c1 = ProjectPointOnPlane(positionWS, p1, n1);
real3 c2 = ProjectPointOnPlane(positionWS, p2, n2);
real3 phongPositionWS = baryCoords.x * c0 + baryCoords.y * c1 + baryCoords.z * c2;
return lerp(positionWS, phongPositionWS, shape);
}
// Reference: http://twvideo01.ubm-us.net/o1/vault/gdc10/slides/Bilodeau_Bill_Direct3D11TutorialTessellation.pdf
// Compute both screen and distance based adaptation - return factor between 0 and 1
real3 GetScreenSpaceTessFactor(real3 p0, real3 p1, real3 p2, real4x4 viewProjectionMatrix, real4 screenSize, real triangleSize)
{
// Get screen space adaptive scale factor
real2 edgeScreenPosition0 = ComputeNormalizedDeviceCoordinates(p0, viewProjectionMatrix) * screenSize.xy;
real2 edgeScreenPosition1 = ComputeNormalizedDeviceCoordinates(p1, viewProjectionMatrix) * screenSize.xy;
real2 edgeScreenPosition2 = ComputeNormalizedDeviceCoordinates(p2, viewProjectionMatrix) * screenSize.xy;
real EdgeScale = 1.0 / triangleSize; // Edge size in reality, but name is simpler
real3 tessFactor;
tessFactor.x = saturate(distance(edgeScreenPosition1, edgeScreenPosition2) * EdgeScale);
tessFactor.y = saturate(distance(edgeScreenPosition0, edgeScreenPosition2) * EdgeScale);
tessFactor.z = saturate(distance(edgeScreenPosition0, edgeScreenPosition1) * EdgeScale);
return tessFactor;
}
real3 GetDistanceBasedTessFactor(real3 p0, real3 p1, real3 p2, real3 cameraPosWS, real tessMinDist, real tessMaxDist)
{
real3 edgePosition0 = 0.5 * (p1 + p2);
real3 edgePosition1 = 0.5 * (p0 + p2);
real3 edgePosition2 = 0.5 * (p0 + p1);
// In case camera-relative rendering is enabled, 'cameraPosWS' is statically known to be 0,
// so the compiler will be able to optimize distance() to length().
real dist0 = distance(edgePosition0, cameraPosWS);
real dist1 = distance(edgePosition1, cameraPosWS);
real dist2 = distance(edgePosition2, cameraPosWS);
// The saturate will handle the produced NaN in case min == max
real fadeDist = tessMaxDist - tessMinDist;
real3 tessFactor;
tessFactor.x = saturate(1.0 - (dist0 - tessMinDist) / fadeDist);
tessFactor.y = saturate(1.0 - (dist1 - tessMinDist) / fadeDist);
tessFactor.z = saturate(1.0 - (dist2 - tessMinDist) / fadeDist);
return tessFactor;
}
real4 CalcTriTessFactorsFromEdgeTessFactors(real3 triVertexFactors)
{
real4 tess;
tess.x = triVertexFactors.x;
tess.y = triVertexFactors.y;
tess.z = triVertexFactors.z;
tess.w = (triVertexFactors.x + triVertexFactors.y + triVertexFactors.z) / 3.0;
return tess;
}

View File

@@ -0,0 +1,198 @@
#ifndef UNITY_TEXTURE_INCLUDED
#define UNITY_TEXTURE_INCLUDED
#ifdef SHADER_API_GLES
#define UNITY_BARE_SAMPLER(n) GLES2UnsupportedSamplerState n
#else
#define UNITY_BARE_SAMPLER(n) SAMPLER(n)
#endif
struct GLES2UnsupportedSamplerState
{
};
UNITY_BARE_SAMPLER(default_sampler_Linear_Repeat);
struct UnitySamplerState
{
UNITY_BARE_SAMPLER(samplerstate);
};
#ifdef SHADER_API_GLES
#define UnityBuildSamplerStateStruct(n) UnityBuildSamplerStateStructInternal()
#else
#define UnityBuildSamplerStateStruct(n) UnityBuildSamplerStateStructInternal(n)
#endif
UnitySamplerState UnityBuildSamplerStateStructInternal(SAMPLER(samplerstate))
{
UnitySamplerState result;
#ifndef SHADER_API_GLES
result.samplerstate = samplerstate;
#endif
return result;
}
struct UnityTexture2D
{
TEXTURE2D(tex);
UNITY_BARE_SAMPLER(samplerstate);
float4 texelSize;
float4 scaleTranslate;
// these functions allows users to convert code using Texture2D to UnityTexture2D by simply changing the type of the variable
// the existing texture macros will call these functions, which will forward the call to the texture appropriately
float4 Sample(UnitySamplerState s, float2 uv) { return SAMPLE_TEXTURE2D(tex, s.samplerstate, uv); }
float4 SampleLevel(UnitySamplerState s, float2 uv, float lod) { return SAMPLE_TEXTURE2D_LOD(tex, s.samplerstate, uv, lod); }
float4 SampleBias(UnitySamplerState s, float2 uv, float bias) { return SAMPLE_TEXTURE2D_BIAS(tex, s.samplerstate, uv, bias); }
float4 SampleGrad(UnitySamplerState s, float2 uv, float2 dpdx, float2 dpdy) { return SAMPLE_TEXTURE2D_GRAD(tex, s.samplerstate, uv, dpdx, dpdy); }
#ifndef SHADER_API_GLES
float CalculateLevelOfDetail(UnitySamplerState s, float2 uv) { return CALCULATE_TEXTURE2D_LOD(tex, s.samplerstate, uv); }
float4 Sample(SAMPLER(s), float2 uv) { return SAMPLE_TEXTURE2D(tex, s, uv); }
float4 SampleLevel(SAMPLER(s), float2 uv, float lod) { return SAMPLE_TEXTURE2D_LOD(tex, s, uv, lod); }
float4 SampleBias(SAMPLER(s), float2 uv, float bias) { return SAMPLE_TEXTURE2D_BIAS(tex, s, uv, bias); }
float4 SampleGrad(SAMPLER(s), float2 uv, float2 dpdx, float2 dpdy) { return SAMPLE_TEXTURE2D_GRAD(tex, s, uv, dpdx, dpdy); }
float4 SampleCmpLevelZero(SAMPLER_CMP(s), float2 uv, float cmp) { return SAMPLE_TEXTURE2D_SHADOW(tex, s, float3(uv, cmp)); }
float4 Load(int3 pixel) { return LOAD_TEXTURE2D_LOD(tex, pixel.xy, pixel.z); }
float CalculateLevelOfDetail(SAMPLER(s), float2 uv) { return CALCULATE_TEXTURE2D_LOD(tex, s, uv); }
#endif
#ifdef PLATFORM_SUPPORT_GATHER
float4 Gather(UnitySamplerState s, float2 uv) { return GATHER_TEXTURE2D(tex, s.samplerstate, uv); }
float4 GatherRed(UnitySamplerState s, float2 uv) { return GATHER_RED_TEXTURE2D(tex, s.samplerstate, uv); }
float4 GatherGreen(UnitySamplerState s, float2 uv) { return GATHER_GREEN_TEXTURE2D(tex, s.samplerstate, uv); }
float4 GatherBlue(UnitySamplerState s, float2 uv) { return GATHER_BLUE_TEXTURE2D(tex, s.samplerstate, uv); }
float4 GatherAlpha(UnitySamplerState s, float2 uv) { return GATHER_ALPHA_TEXTURE2D(tex, s.samplerstate, uv); }
float4 Gather(SAMPLER(s), float2 uv) { return GATHER_TEXTURE2D(tex, s, uv); }
float4 GatherRed(SAMPLER(s), float2 uv) { return GATHER_RED_TEXTURE2D(tex, s, uv); }
float4 GatherGreen(SAMPLER(s), float2 uv) { return GATHER_GREEN_TEXTURE2D(tex, s, uv); }
float4 GatherBlue(SAMPLER(s), float2 uv) { return GATHER_BLUE_TEXTURE2D(tex, s, uv); }
float4 GatherAlpha(SAMPLER(s), float2 uv) { return GATHER_ALPHA_TEXTURE2D(tex, s, uv); }
#endif
};
float4 tex2D(UnityTexture2D tex, float2 uv) { return SAMPLE_TEXTURE2D(tex.tex, tex.samplerstate, uv); }
float4 tex2Dlod(UnityTexture2D tex, float4 uv0l) { return SAMPLE_TEXTURE2D_LOD(tex.tex, tex.samplerstate, uv0l.xy, uv0l.w); }
float4 tex2Dbias(UnityTexture2D tex, float4 uv0b) { return SAMPLE_TEXTURE2D_BIAS(tex.tex, tex.samplerstate, uv0b.xy, uv0b.w); }
#define UnityBuildTexture2DStruct(n) UnityBuildTexture2DStructInternal(TEXTURE2D_ARGS(n, sampler##n), n##_TexelSize, n##_ST)
#define UnityBuildTexture2DStructNoScale(n) UnityBuildTexture2DStructInternal(TEXTURE2D_ARGS(n, sampler##n), n##_TexelSize, float4(1, 1, 0, 0))
UnityTexture2D UnityBuildTexture2DStructInternal(TEXTURE2D_PARAM(tex, samplerstate), float4 texelSize, float4 scaleTranslate)
{
UnityTexture2D result;
result.tex = tex;
#ifndef SHADER_API_GLES
result.samplerstate = samplerstate;
#endif
result.texelSize = texelSize;
result.scaleTranslate = scaleTranslate;
return result;
}
struct UnityTexture2DArray
{
TEXTURE2D_ARRAY(tex);
UNITY_BARE_SAMPLER(samplerstate);
// these functions allows users to convert code using Texture2DArray to UnityTexture2DArray by simply changing the type of the variable
// the existing texture macros will call these functions, which will forward the call to the texture appropriately
#ifndef SHADER_API_GLES
float4 Sample(UnitySamplerState s, float3 uv) { return SAMPLE_TEXTURE2D_ARRAY(tex, s.samplerstate, uv.xy, uv.z); }
float4 SampleLevel(UnitySamplerState s, float3 uv, float lod) { return SAMPLE_TEXTURE2D_ARRAY_LOD(tex, s.samplerstate, uv.xy, uv.z, lod); }
float4 SampleBias(UnitySamplerState s, float3 uv, float bias) { return SAMPLE_TEXTURE2D_ARRAY_BIAS(tex, s.samplerstate, uv.xy, uv.z, bias); }
float4 SampleGrad(UnitySamplerState s, float3 uv, float2 dpdx, float2 dpdy) { return SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, s.samplerstate, uv.xy, uv.z, dpdx, dpdy); }
float4 Sample(SAMPLER(s), float3 uv) { return SAMPLE_TEXTURE2D_ARRAY(tex, s, uv.xy, uv.z); }
float4 SampleLevel(SAMPLER(s), float3 uv, float lod) { return SAMPLE_TEXTURE2D_ARRAY_LOD(tex, s, uv.xy, uv.z, lod); }
float4 SampleBias(SAMPLER(s), float3 uv, float bias) { return SAMPLE_TEXTURE2D_ARRAY_BIAS(tex, s, uv.xy, uv.z, bias); }
float4 SampleGrad(SAMPLER(s), float3 uv, float2 dpdx, float2 dpdy) { return SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, s, uv.xy, uv.z, dpdx, dpdy); }
float4 SampleCmpLevelZero(SAMPLER_CMP(s), float3 uv, float cmp) { return SAMPLE_TEXTURE2D_ARRAY_SHADOW(tex, s, float3(uv.xy, cmp), uv.z); }
float4 Load(int4 pixel) { return LOAD_TEXTURE2D_ARRAY(tex, pixel.xy, pixel.z); }
#endif
};
#define UnityBuildTexture2DArrayStruct(n) UnityBuildTexture2DArrayStructInternal(TEXTURE2D_ARRAY_ARGS(n, sampler##n))
UnityTexture2DArray UnityBuildTexture2DArrayStructInternal(TEXTURE2D_ARRAY_PARAM(tex, samplerstate))
{
UnityTexture2DArray result;
result.tex = tex;
#ifndef SHADER_API_GLES
result.samplerstate = samplerstate;
#endif
return result;
}
struct UnityTextureCube
{
TEXTURECUBE(tex);
UNITY_BARE_SAMPLER(samplerstate);
// these functions allows users to convert code using TextureCube to UnityTextureCube by simply changing the type of the variable
// the existing texture macros will call these functions, which will forward the call to the texture appropriately
float4 Sample(UnitySamplerState s, float3 dir) { return SAMPLE_TEXTURECUBE(tex, s.samplerstate, dir); }
float4 SampleLevel(UnitySamplerState s, float3 dir, float lod) { return SAMPLE_TEXTURECUBE_LOD(tex, s.samplerstate, dir, lod); }
float4 SampleBias(UnitySamplerState s, float3 dir, float bias) { return SAMPLE_TEXTURECUBE_BIAS(tex, s.samplerstate, dir, bias); }
#ifndef SHADER_API_GLES
float4 Sample(SAMPLER(s), float3 dir) { return SAMPLE_TEXTURECUBE(tex, s, dir); }
float4 SampleLevel(SAMPLER(s), float3 dir, float lod) { return SAMPLE_TEXTURECUBE_LOD(tex, s, dir, lod); }
float4 SampleBias(SAMPLER(s), float3 dir, float bias) { return SAMPLE_TEXTURECUBE_BIAS(tex, s, dir, bias); }
#endif
#ifdef PLATFORM_SUPPORT_GATHER
float4 Gather(UnitySamplerState s, float3 dir) { return GATHER_TEXTURECUBE(tex, s.samplerstate, dir); }
float4 Gather(SAMPLER(s), float3 dir) { return GATHER_TEXTURECUBE(tex, s, dir); }
#endif
};
float4 texCUBE(UnityTextureCube tex, float3 dir) { return SAMPLE_TEXTURECUBE(tex.tex, tex.samplerstate, dir); }
float4 texCUBEbias(UnityTextureCube tex, float4 dirBias) { return SAMPLE_TEXTURECUBE_BIAS(tex.tex, tex.samplerstate, dirBias.xyz, dirBias.w); }
#define UnityBuildTextureCubeStruct(n) UnityBuildTextureCubeStructInternal(TEXTURECUBE_ARGS(n, sampler##n))
UnityTextureCube UnityBuildTextureCubeStructInternal(TEXTURECUBE_PARAM(tex, samplerstate))
{
UnityTextureCube result;
result.tex = tex;
#ifndef SHADER_API_GLES
result.samplerstate = samplerstate;
#endif
return result;
}
struct UnityTexture3D
{
TEXTURE3D(tex);
UNITY_BARE_SAMPLER(samplerstate);
// these functions allows users to convert code using Texture3D to UnityTexture3D by simply changing the type of the variable
// the existing texture macros will call these functions, which will forward the call to the texture appropriately
float4 Sample(UnitySamplerState s, float3 uvw) { return SAMPLE_TEXTURE3D(tex, s.samplerstate, uvw); }
#ifndef SHADER_API_GLES
float4 SampleLevel(UnitySamplerState s, float3 uvw, float lod) { return SAMPLE_TEXTURE3D_LOD(tex, s.samplerstate, uvw, lod); }
float4 Sample(SAMPLER(s), float3 uvw) { return SAMPLE_TEXTURE2D(tex, s, uvw); }
float4 SampleLevel(SAMPLER(s), float3 uvw, float lod) { return SAMPLE_TEXTURE2D_LOD(tex, s, uvw, lod); }
float4 Load(int4 pixel) { return LOAD_TEXTURE3D_LOD(tex, pixel.xyz, pixel.w); }
#endif
};
float4 tex3D(UnityTexture3D tex, float3 uvw) { return SAMPLE_TEXTURE3D(tex.tex, tex.samplerstate, uvw); }
#define UnityBuildTexture3DStruct(n) UnityBuildTexture3DStructInternal(TEXTURE3D_ARGS(n, sampler##n))
UnityTexture3D UnityBuildTexture3DStructInternal(TEXTURE3D_PARAM(tex, samplerstate))
{
UnityTexture3D result;
result.tex = tex;
#ifndef SHADER_API_GLES
result.samplerstate = samplerstate;
#endif
return result;
}
#endif // UNITY_TEXTURE_INCLUDED

View File

@@ -0,0 +1,421 @@
#ifndef TEXTURESTACK_include
#define TEXTURESTACK_include
#define GRA_HLSL_5 1
#define GRA_ROW_MAJOR 1
#define GRA_TEXTURE_ARRAY_SUPPORT 1
#define GRA_PACK_RESOLVE_OUTPUT 0
#if SHADER_API_PSSL
#define GRA_NO_UNORM 1
#endif
#include "VirtualTexturing.hlsl"
#include "Packing.hlsl"
/*
This header adds the following pseudo definitions. Actual types etc may vary depending
on vt- being on or off.
struct StackInfo { opaque struct ... }
StackInfo PrepareStack(float2 uv, Stack object);
float4 SampleStack(StackInfo info, Texture tex);
To use this in your materials add the following to various locations in the shader:
In shaderlab "Properties" section add:
[TextureStack.MyFancyStack] DiffuseTexture ("DiffuseTexture", 2D) = "white" {}
[TextureStack.MyFancyStack] NormalTexture ("NormalTexture", 2D) = "white" {}
This will declare a texture stack with two textures.
Then add the following to the PerMaterial constant buffer:
CBUFFER_START(UnityPerMaterial)
...
DECLARE_STACK_CB(MyFancyStack)
...
CBUFFER_END
Then in your shader root add the following:
...
DECLARE_STACK(MyFancyStack, DiffuseTexture)
or
DECLARE_STACK2(MyFancyStack, DiffuseTexture, NormalTexture)
or
DECLARE_STACK3(MyFancyStack, TextureSlot1, TextureSlot2, TextureSlot2)
etc...
NOTE: The Stack shaderlab property and DECLARE_STACKn define need to match i.e. the same name and same texture slots.
Then in the pixel shader function (likely somewhere at the beginning) do a call:
StackInfo info = PrepareStack(uvs, MyFancyStack);
Then later on when you want to sample the actual texture do a call(s):
float4 color = SampleStack(info, TextureSlot1);
float4 color2 = SampleStack(info, TextureSlot2);
...
The above steps can be repeated for multiple stacks. But be sure that when using the SampleStack you always
pass in the result of the PrepareStack for the correct stack the texture belongs to.
*/
#if defined(UNITY_VIRTUAL_TEXTURING) && !defined(FORCE_VIRTUAL_TEXTURING_OFF)
struct StackInfo
{
GraniteLookupData lookupData;
GraniteLODLookupData lookupDataLod;
float4 resolveOutput;
};
struct VTProperty
{
GraniteConstantBuffers grCB;
GraniteTranslationTexture translationTable;
GraniteCacheTexture cacheLayer[4];
int layerCount;
int layerIndex[4];
};
#ifdef TEXTURESTACK_CLAMP
#define GR_LOOKUP Granite_Lookup_Clamp_Linear
#define GR_LOOKUP_LOD Granite_Lookup_Clamp
#else
#define GR_LOOKUP Granite_Lookup_Anisotropic
#define GR_LOOKUP_LOD Granite_Lookup
#endif
// This can be used by certain resolver implementations to override screen space derivatives
#ifndef RESOLVE_SCALE_OVERRIDE
#define RESOLVE_SCALE_OVERRIDE float2(1,1)
#endif
StructuredBuffer<GraniteTilesetConstantBuffer> _VTTilesetBuffer;
#define DECLARE_STACK_CB(stackName) \
float4 stackName##_atlasparams[2]
#define DECLARE_STACK_BASE(stackName) \
TEXTURE2D(stackName##_transtab);\
SAMPLER(sampler##stackName##_transtab);\
\
GraniteTilesetConstantBuffer GetConstantBuffer_##stackName() \
{ \
int idx = (int)stackName##_atlasparams[1].w; \
GraniteTilesetConstantBuffer graniteParamBlock; \
graniteParamBlock = _VTTilesetBuffer[idx]; \
\
graniteParamBlock.data[0][2][0] *= RESOLVE_SCALE_OVERRIDE.x; \
graniteParamBlock.data[0][3][0] *= RESOLVE_SCALE_OVERRIDE.y; \
\
return graniteParamBlock; \
} \
StackInfo PrepareVT_##stackName(VtInputParameters par)\
{\
GraniteStreamingTextureConstantBuffer textureParamBlock;\
textureParamBlock.data[0] = stackName##_atlasparams[0];\
textureParamBlock.data[1] = stackName##_atlasparams[1];\
\
GraniteTilesetConstantBuffer graniteParamBlock = GetConstantBuffer_##stackName(); \
\
GraniteConstantBuffers grCB;\
grCB.tilesetBuffer = graniteParamBlock;\
grCB.streamingTextureBuffer = textureParamBlock;\
\
GraniteTranslationTexture translationTable;\
translationTable.Texture = stackName##_transtab;\
translationTable.Sampler = sampler##stackName##_transtab;\
\
StackInfo info;\
VirtualTexturingLookup(grCB, translationTable, par, info.lookupData, info.resolveOutput);\
return info;\
}
// TODO: we could replace all uses of GetConstantBuffer_*() with this one:
GraniteTilesetConstantBuffer GetConstantBuffer(GraniteStreamingTextureConstantBuffer textureParamBlock)
{
int idx = (int)textureParamBlock.data[1].w;
GraniteTilesetConstantBuffer graniteParamBlock;
graniteParamBlock = _VTTilesetBuffer[idx];
graniteParamBlock.data[0][2][0] *= RESOLVE_SCALE_OVERRIDE.x;
graniteParamBlock.data[0][3][0] *= RESOLVE_SCALE_OVERRIDE.y;
return graniteParamBlock;
}
#define jj2(a, b) a##b
#define jj(a, b) jj2(a, b)
#define DECLARE_STACK_LAYER(stackName, layerSamplerName, layerIndex) \
TEXTURE2D_ARRAY(stackName##_c##layerIndex);\
SAMPLER(sampler##stackName##_c##layerIndex);\
\
float4 SampleVT_##layerSamplerName(StackInfo info, int lodCalculation, int quality)\
{\
GraniteStreamingTextureConstantBuffer textureParamBlock;\
textureParamBlock.data[0] = stackName##_atlasparams[0];\
textureParamBlock.data[1] = stackName##_atlasparams[1];\
\
GraniteTilesetConstantBuffer graniteParamBlock = GetConstantBuffer_##stackName(); \
\
GraniteConstantBuffers grCB;\
grCB.tilesetBuffer = graniteParamBlock;\
grCB.streamingTextureBuffer = textureParamBlock;\
\
GraniteCacheTexture cache;\
cache.TextureArray = stackName##_c##layerIndex;\
cache.Sampler = sampler##stackName##_c##layerIndex;\
\
float4 output;\
VirtualTexturingSample(grCB.tilesetBuffer, info.lookupData, cache, layerIndex, lodCalculation, quality, output);\
return output;\
}
#define DECLARE_BUILD_PROPERTIES(stackName, layers, layer0Index, layer1Index, layer2Index, layer3Index)\
VTProperty BuildVTProperties_##stackName()\
{\
VTProperty vtProperty; \
\
GraniteStreamingTextureConstantBuffer textureParamBlock; \
textureParamBlock.data[0] = stackName##_atlasparams[0]; \
textureParamBlock.data[1] = stackName##_atlasparams[1]; \
\
vtProperty.grCB.tilesetBuffer = GetConstantBuffer(textureParamBlock); \
vtProperty.grCB.streamingTextureBuffer = textureParamBlock; \
\
vtProperty.translationTable.Texture = stackName##_transtab; \
vtProperty.translationTable.Sampler = sampler##stackName##_transtab; \
\
vtProperty.layerCount = layers; \
vtProperty.layerIndex[0] = layer0Index; \
vtProperty.layerIndex[1] = layer1Index; \
vtProperty.layerIndex[2] = layer2Index; \
vtProperty.layerIndex[3] = layer3Index; \
\
vtProperty.cacheLayer[0].TextureArray = stackName##_c##layer0Index; \
vtProperty.cacheLayer[0].Sampler = sampler##stackName##_c##layer0Index;\
vtProperty.cacheLayer[1].TextureArray = stackName##_c##layer1Index; \
vtProperty.cacheLayer[1].Sampler = sampler##stackName##_c##layer1Index;\
vtProperty.cacheLayer[2].TextureArray = stackName##_c##layer2Index; \
vtProperty.cacheLayer[2].Sampler = sampler##stackName##_c##layer2Index;\
vtProperty.cacheLayer[3].TextureArray = stackName##_c##layer3Index; \
vtProperty.cacheLayer[3].Sampler = sampler##stackName##_c##layer3Index;\
\
return vtProperty; \
}
#define DECLARE_STACK(stackName, layer0SamplerName)\
DECLARE_STACK_BASE(stackName)\
DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\
DECLARE_BUILD_PROPERTIES(stackName, 1, 0, 0, 0, 0)
#define DECLARE_STACK2(stackName, layer0SamplerName, layer1SamplerName)\
DECLARE_STACK_BASE(stackName)\
DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\
DECLARE_STACK_LAYER(stackName, layer1SamplerName, 1)\
DECLARE_BUILD_PROPERTIES(stackName, 2, 0, 1, 1, 1)
#define DECLARE_STACK3(stackName, layer0SamplerName, layer1SamplerName, layer2SamplerName)\
DECLARE_STACK_BASE(stackName)\
DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\
DECLARE_STACK_LAYER(stackName, layer1SamplerName, 1)\
DECLARE_STACK_LAYER(stackName, layer2SamplerName, 2)\
DECLARE_BUILD_PROPERTIES(stackName, 3, 0, 1, 2, 2)
#define DECLARE_STACK4(stackName, layer0SamplerName, layer1SamplerName, layer2SamplerName, layer3SamplerName)\
DECLARE_STACK_BASE(stackName)\
DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\
DECLARE_STACK_LAYER(stackName, layer1SamplerName, 1)\
DECLARE_STACK_LAYER(stackName, layer2SamplerName, 2)\
DECLARE_STACK_LAYER(stackName, layer3SamplerName, 3)\
DECLARE_BUILD_PROPERTIES(stackName, 4, 0, 1, 2, 3)
#define PrepareStack(inputParams, stackName) PrepareVT_##stackName(inputParams)
#define SampleStack(info, lodMode, quality, textureName) SampleVT_##textureName(info, lodMode, quality)
#define GetResolveOutput(info) info.resolveOutput
#define PackResolveOutput(output) Granite_PackTileId(output)
StackInfo PrepareVT(VTProperty vtProperty, VtInputParameters vtParams)
{
StackInfo info;
VirtualTexturingLookup(vtProperty.grCB, vtProperty.translationTable, vtParams, info.lookupData, info.resolveOutput);
return info;
}
// NOTE: layerIndex here can only be an immediate constant (i.e. 0,1,2, or 3) -- it CANNOT be a variable or expression
// this is because we use macro concatentation on it when VT is disabled
float4 SampleVTLayer(VTProperty vtProperty, VtInputParameters vtParams, StackInfo info, int layerIndex)
{
float4 result;
VirtualTexturingSample(vtProperty.grCB.tilesetBuffer, info.lookupData, vtProperty.cacheLayer[layerIndex], vtProperty.layerIndex[layerIndex], vtParams.levelMode, vtParams.sampleQuality, result);
return result;
}
float4 GetPackedVTFeedback(float4 feedback)
{
return Granite_PackTileId(feedback);
}
#define VIRTUAL_TEXTURING_SHADER_ENABLED
#else
// Virtual Texturing Disabled -- fallback to regular texture sampling
#define DECLARE_BUILD_PROPERTIES(stackName, layers, layer0, layer1, layer2, layer3)\
VTProperty BuildVTProperties_##stackName()\
{\
VTProperty vtProperty; \
\
vtProperty.layerCount = layers; \
vtProperty.Layer0 = layer0; \
vtProperty.Layer1 = layer1; \
vtProperty.Layer2 = layer2; \
vtProperty.Layer3 = layer3; \
\
ASSIGN_SAMPLER(vtProperty.samplerLayer0, sampler##layer0); \
ASSIGN_SAMPLER(vtProperty.samplerLayer1, sampler##layer1); \
ASSIGN_SAMPLER(vtProperty.samplerLayer2, sampler##layer2); \
ASSIGN_SAMPLER(vtProperty.samplerLayer3, sampler##layer3); \
\
return vtProperty; \
}
// Stacks amount to nothing when VT is off
#define DECLARE_STACK(stackName, layer0) \
DECLARE_BUILD_PROPERTIES(stackName, 1, layer0, layer0, layer0, layer0)
#define DECLARE_STACK2(stackName, layer0, layer1) \
DECLARE_BUILD_PROPERTIES(stackName, 2, layer0, layer1, layer1, layer1)
#define DECLARE_STACK3(stackName, layer0, layer1, layer2) \
DECLARE_BUILD_PROPERTIES(stackName, 3, layer0, layer1, layer2, layer2)
#define DECLARE_STACK4(stackName, layer0, layer1, layer2, layer3) \
DECLARE_BUILD_PROPERTIES(stackName, 4, layer0, layer1, layer2, layer3)
#define DECLARE_STACK_CB(stackName)
// Info is just the uv's
// We could do a straight #define StackInfo float2 but this makes it a bit more type safe
// and allows us to do things like function overloads,...
struct StackInfo
{
VtInputParameters vt;
};
struct VTProperty
{
int layerCount;
TEXTURE2D(Layer0);
TEXTURE2D(Layer1);
TEXTURE2D(Layer2);
TEXTURE2D(Layer3);
#ifndef SHADER_API_GLES
SAMPLER(samplerLayer0);
SAMPLER(samplerLayer1);
SAMPLER(samplerLayer2);
SAMPLER(samplerLayer3);
#endif
};
StackInfo MakeStackInfo(VtInputParameters vt)
{
StackInfo result;
result.vt = vt;
return result;
}
// Prepare just passes the texture coord around
#define PrepareStack(inputParams, stackName) MakeStackInfo(inputParams)
// Sample just samples the texture
#define SampleStack(info, vtLevelMode, quality, texture) \
SampleVTFallbackToTexture(info, vtLevelMode, TEXTURE2D_ARGS(texture, sampler##texture))
float4 SampleVTFallbackToTexture(StackInfo info, int vtLevelMode, TEXTURE2D_PARAM(layerTexture, layerSampler))
{
if (vtLevelMode == VtLevel_Automatic)
return SAMPLE_TEXTURE2D(layerTexture, layerSampler, info.vt.uv);
else if (vtLevelMode == VtLevel_Lod)
return SAMPLE_TEXTURE2D_LOD(layerTexture, layerSampler, info.vt.uv, info.vt.lodOrOffset);
else if (vtLevelMode == VtLevel_Bias)
return SAMPLE_TEXTURE2D_BIAS(layerTexture, layerSampler, info.vt.uv, info.vt.lodOrOffset);
else // vtLevelMode == VtLevel_Derivatives
return SAMPLE_TEXTURE2D_GRAD(layerTexture, layerSampler, info.vt.uv, info.vt.dx, info.vt.dy);
}
StackInfo PrepareVT(VTProperty vtProperty, VtInputParameters vtParams)
{
StackInfo result;
result.vt = vtParams;
return result;
}
// NOTE: layerIndex here can only be an immediate constant (i.e. 0,1,2, or 3) -- it CANNOT be a variable or expression
// this is because we use macro concatentation on it when VT is disabled
#define SampleVTLayer(vtProperty, vtParams, info, layerIndex) \
SampleVTFallbackToTexture(info, vtParams.levelMode, TEXTURE2D_ARGS(vtProperty.Layer##layerIndex, vtProperty.samplerLayer##layerIndex))
// Resolve does nothing
#define GetResolveOutput(info) float4(1,1,1,1)
#define PackResolveOutput(output) output
#define GetPackedVTFeedback(feedback) feedback
#endif
// Shared code between VT enabled and VT disabled, adding TextureType handling
// these texture types should be kept in sync with LayerTextureType in C# code
#define TEXTURETYPE_DEFAULT 0 // LayerTextureType.Default
#define TEXTURETYPE_NORMALTANGENTSPACE 1 // LayerTextureType.NormalTangentSpace
#define TEXTURETYPE_NORMALOBJECTSPACE 2 // LayerTextureType.NormalObjectSpace
struct VTPropertyWithTextureType
{
VTProperty vtProperty;
int layerTextureType[4];
};
VTPropertyWithTextureType AddTextureType(VTProperty vtProperty, int layer0TextureType, int layer1TextureType = TEXTURETYPE_DEFAULT, int layer2TextureType = TEXTURETYPE_DEFAULT, int layer3TextureType = TEXTURETYPE_DEFAULT)
{
VTPropertyWithTextureType result;
result.vtProperty = vtProperty;
result.layerTextureType[0] = layer0TextureType;
result.layerTextureType[1] = layer1TextureType;
result.layerTextureType[2] = layer2TextureType;
result.layerTextureType[3] = layer3TextureType;
return result;
}
float4 ApplyTextureType(float4 value, int textureType)
{
// NOTE: when textureType is a compile-time constant, the branches compile out
if (textureType == TEXTURETYPE_NORMALTANGENTSPACE)
{
value.rgb = UnpackNormalmapRGorAG(value);
}
else if (textureType == TEXTURETYPE_NORMALOBJECTSPACE)
{
value.rgb = UnpackNormalRGB(value);
}
return value;
}
// if we _could_ express it as a function, the function signature would be:
// float4 SampleVTLayerWithTextureType(VTPropertyWithTextureType vtProperty, VtInputParameters vtParams, StackInfo info, [immediate] int layerIndex)
// NOTE: layerIndex here can only be an immediate constant (i.e. 0,1,2, or 3) -- it CANNOT be a variable or expression
// this is because we use macro concatentation on it when VT is disabled
#define SampleVTLayerWithTextureType(vtProperty, vtParams, info, layerIndex) \
ApplyTextureType(SampleVTLayer(vtProperty.vtProperty, vtParams, info, layerIndex), vtProperty.layerTextureType[layerIndex])
#endif //TEXTURESTACK_include

View File

@@ -0,0 +1,3 @@
{
"name": "Unity.RenderPipelines.Core.ShaderLibrary"
}

View File

@@ -0,0 +1,238 @@
#ifndef UNITY_DOTS_INSTANCING_INCLUDED
#define UNITY_DOTS_INSTANCING_INCLUDED
#ifdef UNITY_DOTS_INSTANCING_ENABLED
/*
Here's a bit of python code to generate these repetitive typespecs without
a lot of C macro magic
def print_dots_instancing_typespecs(elem_type, id_char, elem_size):
print(f"#define UNITY_DOTS_INSTANCING_TYPESPEC_{elem_type} {id_char}{elem_size}")
for y in range(1, 5):
for x in range(1, 5):
rows = "" if y == 1 else f"x{y}"
size = elem_size * x * y
print(f"#define UNITY_DOTS_INSTANCING_TYPESPEC_{elem_type}{x}{rows} {id_char}{size}")
for t, c, sz in (
('float', 'F', 4),
('int', 'I', 4),
('uint', 'U', 4),
('half', 'H', 2)
):
print_dots_instancing_typespecs(t, c, sz)
*/
#define UNITY_DOTS_INSTANCING_TYPESPEC_float F4
#define UNITY_DOTS_INSTANCING_TYPESPEC_float1 F4
#define UNITY_DOTS_INSTANCING_TYPESPEC_float2 F8
#define UNITY_DOTS_INSTANCING_TYPESPEC_float3 F12
#define UNITY_DOTS_INSTANCING_TYPESPEC_float4 F16
#define UNITY_DOTS_INSTANCING_TYPESPEC_float1x2 F8
#define UNITY_DOTS_INSTANCING_TYPESPEC_float2x2 F16
#define UNITY_DOTS_INSTANCING_TYPESPEC_float3x2 F24
#define UNITY_DOTS_INSTANCING_TYPESPEC_float4x2 F32
#define UNITY_DOTS_INSTANCING_TYPESPEC_float1x3 F12
#define UNITY_DOTS_INSTANCING_TYPESPEC_float2x3 F24
#define UNITY_DOTS_INSTANCING_TYPESPEC_float3x3 F36
#define UNITY_DOTS_INSTANCING_TYPESPEC_float4x3 F48
#define UNITY_DOTS_INSTANCING_TYPESPEC_float1x4 F16
#define UNITY_DOTS_INSTANCING_TYPESPEC_float2x4 F32
#define UNITY_DOTS_INSTANCING_TYPESPEC_float3x4 F48
#define UNITY_DOTS_INSTANCING_TYPESPEC_float4x4 F64
#define UNITY_DOTS_INSTANCING_TYPESPEC_int I4
#define UNITY_DOTS_INSTANCING_TYPESPEC_int1 I4
#define UNITY_DOTS_INSTANCING_TYPESPEC_int2 I8
#define UNITY_DOTS_INSTANCING_TYPESPEC_int3 I12
#define UNITY_DOTS_INSTANCING_TYPESPEC_int4 I16
#define UNITY_DOTS_INSTANCING_TYPESPEC_int1x2 I8
#define UNITY_DOTS_INSTANCING_TYPESPEC_int2x2 I16
#define UNITY_DOTS_INSTANCING_TYPESPEC_int3x2 I24
#define UNITY_DOTS_INSTANCING_TYPESPEC_int4x2 I32
#define UNITY_DOTS_INSTANCING_TYPESPEC_int1x3 I12
#define UNITY_DOTS_INSTANCING_TYPESPEC_int2x3 I24
#define UNITY_DOTS_INSTANCING_TYPESPEC_int3x3 I36
#define UNITY_DOTS_INSTANCING_TYPESPEC_int4x3 I48
#define UNITY_DOTS_INSTANCING_TYPESPEC_int1x4 I16
#define UNITY_DOTS_INSTANCING_TYPESPEC_int2x4 I32
#define UNITY_DOTS_INSTANCING_TYPESPEC_int3x4 I48
#define UNITY_DOTS_INSTANCING_TYPESPEC_int4x4 I64
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint U4
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1 U4
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2 U8
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3 U12
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4 U16
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1x2 U8
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2x2 U16
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3x2 U24
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4x2 U32
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1x3 U12
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2x3 U24
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3x3 U36
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4x3 U48
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1x4 U16
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2x4 U32
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3x4 U48
#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4x4 U64
#define UNITY_DOTS_INSTANCING_TYPESPEC_half H2
#define UNITY_DOTS_INSTANCING_TYPESPEC_half1 H2
#define UNITY_DOTS_INSTANCING_TYPESPEC_half2 H4
#define UNITY_DOTS_INSTANCING_TYPESPEC_half3 H6
#define UNITY_DOTS_INSTANCING_TYPESPEC_half4 H8
#define UNITY_DOTS_INSTANCING_TYPESPEC_half1x2 H4
#define UNITY_DOTS_INSTANCING_TYPESPEC_half2x2 H8
#define UNITY_DOTS_INSTANCING_TYPESPEC_half3x2 H12
#define UNITY_DOTS_INSTANCING_TYPESPEC_half4x2 H16
#define UNITY_DOTS_INSTANCING_TYPESPEC_half1x3 H6
#define UNITY_DOTS_INSTANCING_TYPESPEC_half2x3 H12
#define UNITY_DOTS_INSTANCING_TYPESPEC_half3x3 H18
#define UNITY_DOTS_INSTANCING_TYPESPEC_half4x3 H24
#define UNITY_DOTS_INSTANCING_TYPESPEC_half1x4 H8
#define UNITY_DOTS_INSTANCING_TYPESPEC_half2x4 H16
#define UNITY_DOTS_INSTANCING_TYPESPEC_half3x4 H24
#define UNITY_DOTS_INSTANCING_TYPESPEC_half4x4 H32
#define UNITY_DOTS_INSTANCING_CONCAT2(a, b) a ## b
#define UNITY_DOTS_INSTANCING_CONCAT4(a, b, c, d) a ## b ## c ## d
#define UNITY_DOTS_INSTANCING_CONCAT_WITHOUT_METADATA(metadata_prefix, typespec, metadata_underscore_var) UNITY_DOTS_INSTANCING_CONCAT4(metadata_prefix, typespec, _, metadata_underscore_var)
#define UNITY_DOTS_INSTANCING_CONCAT_WITH_METADATA(metadata_prefix, typespec, name) UNITY_DOTS_INSTANCING_CONCAT4(metadata_prefix, typespec, _Metadata_, name)
// Metadata constants for properties have the following name format:
// unity_DOTSInstancing_<Type><Size>_Metadata_<Name>
// where
// <Type> is a single character element type specifier (e.g. F for float4x4)
// F = float, I = int, U = uint, H = half
// <Size> is the total size of the property in bytes (e.g. 64 for float4x4)
// <Name> is the name of the property
#define UNITY_DOTS_INSTANCED_METADATA_NAME(type, name) UNITY_DOTS_INSTANCING_CONCAT_WITH_METADATA(unity_DOTSInstancing_, UNITY_DOTS_INSTANCING_CONCAT2(UNITY_DOTS_INSTANCING_TYPESPEC_, type), name)
#define UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(type, metadata_underscore_var) UNITY_DOTS_INSTANCING_CONCAT_WITHOUT_METADATA(unity_DOTSInstancing_, UNITY_DOTS_INSTANCING_CONCAT2(UNITY_DOTS_INSTANCING_TYPESPEC_, type), metadata_underscore_var)
#define UNITY_DOTS_INSTANCING_START(name) cbuffer UnityDOTSInstancing_##name {
#define UNITY_DOTS_INSTANCING_END(name) }
#define UNITY_DOTS_INSTANCED_PROP(type, name) uint UNITY_DOTS_INSTANCED_METADATA_NAME(type, name);
// There is a separate FROM_MACRO variant to be used in macros of the form
// #define <MACRO_NAME> UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(float4, Metadata_<MACRO_NAME>)
// These kinds of macros can be used to have shader code load constants from DOTS instancing
// as if they were normal constants.
// The reason for having the FROM_MACRO variant is that the fxc shader preprocessor is buggy,
// and refuses to expand macros correctly if the macro body contains the macro itself.
// The correct behavior would be for the macro name to appear in the expansion as is (i.e. no recursion),
// but fxc's preprocessor completely breaks down in this situation.
#define UNITY_ACCESS_DOTS_INSTANCED_PROP(type, var) LoadDOTSInstancedData_##type(UNITY_DOTS_INSTANCED_METADATA_NAME(type, var))
#define UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(type, metadata_underscore_var) LoadDOTSInstancedData_##type(UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(type, metadata_underscore_var))
#define UNITY_ACCESS_DOTS_AND_TRADITIONAL_INSTANCED_PROP(type, arr, var) LoadDOTSInstancedData_##type(UNITY_DOTS_INSTANCED_METADATA_NAME(type, var))
// TODO: Shader feature level to compute only
ByteAddressBuffer unity_DOTSInstanceData;
// The data has to be wrapped inside a struct, otherwise the instancing code path
// on some platforms does not trigger.
struct DOTSVisibleData
{
uint4 VisibleData;
};
// The name of this cbuffer has to start with "UnityInstancing" and a struct so it's
// detected as an "instancing cbuffer" by some platforms that use string matching
// to detect this.
CBUFFER_START(UnityInstancingDOTS_InstanceVisibility)
DOTSVisibleData unity_DOTSVisibleInstances[UNITY_INSTANCED_ARRAY_SIZE];
CBUFFER_END
uint GetDOTSInstanceIndex()
{
return unity_DOTSVisibleInstances[unity_InstanceID].VisibleData.x;
}
uint ComputeDOTSInstanceDataAddress(uint metadata, uint stride)
{
uint isOverridden = metadata & 0x80000000;
uint baseAddress = metadata & 0x7fffffff;
uint offset = isOverridden
? (GetDOTSInstanceIndex() * stride)
: 0;
return baseAddress + offset;
}
#define DEFINE_DOTS_LOAD_INSTANCE_SCALAR(type, conv, sizeof_type) \
type LoadDOTSInstancedData_##type(uint metadata) \
{ \
uint address = ComputeDOTSInstanceDataAddress(metadata, sizeof_type); \
return conv(unity_DOTSInstanceData.Load(address)); \
}
#define DEFINE_DOTS_LOAD_INSTANCE_VECTOR(type, width, conv, sizeof_type) \
type##width LoadDOTSInstancedData_##type##width(uint metadata) \
{ \
uint address = ComputeDOTSInstanceDataAddress(metadata, sizeof_type * width); \
return conv(unity_DOTSInstanceData.Load##width(address)); \
}
DEFINE_DOTS_LOAD_INSTANCE_SCALAR(float, asfloat, 4)
DEFINE_DOTS_LOAD_INSTANCE_SCALAR(int, int, 4)
DEFINE_DOTS_LOAD_INSTANCE_SCALAR(uint, uint, 4)
DEFINE_DOTS_LOAD_INSTANCE_SCALAR(half, half, 2)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(float, 2, asfloat, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(float, 3, asfloat, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(float, 4, asfloat, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(int, 2, int2, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(int, 3, int3, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(int, 4, int4, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(uint, 2, uint2, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(uint, 3, uint3, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(uint, 4, uint4, 4)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(half, 2, half2, 2)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(half, 3, half3, 2)
DEFINE_DOTS_LOAD_INSTANCE_VECTOR(half, 4, half4, 2)
// TODO: Other matrix sizes
float4x4 LoadDOTSInstancedData_float4x4(uint metadata)
{
uint address = ComputeDOTSInstanceDataAddress(metadata, 4 * 16);
float4 p1 = asfloat(unity_DOTSInstanceData.Load4(address + 0 * 16));
float4 p2 = asfloat(unity_DOTSInstanceData.Load4(address + 1 * 16));
float4 p3 = asfloat(unity_DOTSInstanceData.Load4(address + 2 * 16));
float4 p4 = asfloat(unity_DOTSInstanceData.Load4(address + 3 * 16));
return float4x4(
p1.x, p2.x, p3.x, p4.x,
p1.y, p2.y, p3.y, p4.y,
p1.z, p2.z, p3.z, p4.z,
p1.w, p2.w, p3.w, p4.w);
}
float4x4 LoadDOTSInstancedData(float4x4 dummy, uint metadata) { return LoadDOTSInstancedData_float4x4(metadata); }
float4x4 LoadDOTSInstancedData_float4x4_from_float3x4(uint metadata)
{
uint address = ComputeDOTSInstanceDataAddress(metadata, 3 * 16);
float4 p1 = asfloat(unity_DOTSInstanceData.Load4(address + 0 * 16));
float4 p2 = asfloat(unity_DOTSInstanceData.Load4(address + 1 * 16));
float4 p3 = asfloat(unity_DOTSInstanceData.Load4(address + 2 * 16));
return float4x4(
p1.x, p1.w, p2.z, p3.y,
p1.y, p2.x, p2.w, p3.z,
p1.z, p2.y, p3.x, p3.w,
0.0, 0.0, 0.0, 1.0
);
}
float2x4 LoadDOTSInstancedData_float2x4(uint metadata)
{
uint address = ComputeDOTSInstanceDataAddress(metadata, 4 * 8);
return float2x4(
asfloat(unity_DOTSInstanceData.Load4(address + 0 * 8)),
asfloat(unity_DOTSInstanceData.Load4(address + 1 * 8)));
}
float2x4 LoadDOTSInstancedData(float2x4 dummy, uint metadata) { return LoadDOTSInstancedData_float2x4(metadata); }
#undef DEFINE_DOTS_LOAD_INSTANCE_SCALAR
#undef DEFINE_DOTS_LOAD_INSTANCE_VECTOR
#endif // UNITY_DOTS_INSTANCING_ENABLED
#endif // UNITY_DOTS_INSTANCING_INCLUDED

View File

@@ -0,0 +1,414 @@
#ifndef UNITY_INSTANCING_INCLUDED
#define UNITY_INSTANCING_INCLUDED
#if SHADER_TARGET >= 35 && (defined(SHADER_API_D3D11) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE) || defined(SHADER_API_XBOXONE) || defined(SHADER_API_GAMECORE) || defined(SHADER_API_PSSL) || defined(SHADER_API_VULKAN) || defined(SHADER_API_METAL))
#define UNITY_SUPPORT_INSTANCING
#endif
#if defined(SHADER_API_SWITCH)
#define UNITY_SUPPORT_INSTANCING
#endif
#if defined(SHADER_API_D3D11) || defined(SHADER_API_GLCORE) || defined(SHADER_API_GLES3) || defined(SHADER_API_VULKAN)
#define UNITY_SUPPORT_STEREO_INSTANCING
#endif
// These platforms support dynamically adjusting the instancing CB size according to the current batch.
#if defined(SHADER_API_D3D11) || defined(SHADER_API_GLCORE) || defined(SHADER_API_GLES3) || defined(SHADER_API_METAL) || defined(SHADER_API_PSSL) || defined(SHADER_API_VULKAN) || defined(SHADER_API_SWITCH)
#define UNITY_INSTANCING_SUPPORT_FLEXIBLE_ARRAY_SIZE
#endif
#if defined(SHADER_TARGET_SURFACE_ANALYSIS) && defined(UNITY_SUPPORT_INSTANCING)
#undef UNITY_SUPPORT_INSTANCING
#endif
////////////////////////////////////////////////////////
// instancing paths
// - UNITY_INSTANCING_ENABLED Defined if instancing path is taken.
// - UNITY_PROCEDURAL_INSTANCING_ENABLED Defined if procedural instancing path is taken.
// - UNITY_STEREO_INSTANCING_ENABLED Defined if stereo instancing path is taken.
// - UNITY_ANY_INSTANCING_ENABLED Defined if any instancing path is taken
#if defined(UNITY_SUPPORT_INSTANCING) && defined(INSTANCING_ON)
#define UNITY_INSTANCING_ENABLED
#endif
#if defined(UNITY_SUPPORT_INSTANCING) && defined(PROCEDURAL_INSTANCING_ON)
#define UNITY_PROCEDURAL_INSTANCING_ENABLED
#endif
#if defined(UNITY_SUPPORT_INSTANCING) && defined(DOTS_INSTANCING_ON)
#define UNITY_DOTS_INSTANCING_ENABLED
#endif
#if defined(UNITY_SUPPORT_STEREO_INSTANCING) && defined(STEREO_INSTANCING_ON)
#define UNITY_STEREO_INSTANCING_ENABLED
#endif
#if defined(UNITY_INSTANCING_ENABLED) || defined(UNITY_PROCEDURAL_INSTANCING_ENABLED) || defined(UNITY_DOTS_INSTANCING_ENABLED) || defined(UNITY_STEREO_INSTANCING_ENABLED)
#define UNITY_ANY_INSTANCING_ENABLED 1
#else
#define UNITY_ANY_INSTANCING_ENABLED 0
#endif
#if defined(DOTS_INSTANCING_ON) && (SHADER_TARGET < 45)
#error The DOTS_INSTANCING_ON keyword requires shader model 4.5 or greater ("#pragma target 4.5" or greater).
#endif
#if defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE) || defined(SHADER_API_METAL) || defined(SHADER_API_VULKAN)
// These platforms have constant buffers disabled normally, but not here (see CBUFFER_START/CBUFFER_END in HLSLSupport.cginc).
#define UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(name) cbuffer name {
#define UNITY_INSTANCING_CBUFFER_SCOPE_END }
#else
#define UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(name) CBUFFER_START(name)
#define UNITY_INSTANCING_CBUFFER_SCOPE_END CBUFFER_END
#endif
////////////////////////////////////////////////////////
// basic instancing setups
// - UNITY_VERTEX_INPUT_INSTANCE_ID Declare instance ID field in vertex shader input / output struct.
// - UNITY_GET_INSTANCE_ID (Internal) Get the instance ID from input struct.
#if UNITY_ANY_INSTANCING_ENABLED
// A global instance ID variable that functions can directly access.
static uint unity_InstanceID;
// Don't make UnityDrawCallInfo an actual CB on GL
#if !defined(SHADER_API_GLES3) && !defined(SHADER_API_GLCORE)
UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(UnityDrawCallInfo)
#endif
int unity_BaseInstanceID;
int unity_InstanceCount;
#if !defined(SHADER_API_GLES3) && !defined(SHADER_API_GLCORE)
UNITY_INSTANCING_CBUFFER_SCOPE_END
#endif
#ifdef SHADER_API_PSSL
#define DEFAULT_UNITY_VERTEX_INPUT_INSTANCE_ID uint instanceID;
#define UNITY_GET_INSTANCE_ID(input) _GETINSTANCEID(input)
#else
#define DEFAULT_UNITY_VERTEX_INPUT_INSTANCE_ID uint instanceID : SV_InstanceID;
#define UNITY_GET_INSTANCE_ID(input) input.instanceID
#endif
#else
#define DEFAULT_UNITY_VERTEX_INPUT_INSTANCE_ID
#endif // UNITY_INSTANCING_ENABLED || UNITY_PROCEDURAL_INSTANCING_ENABLED || UNITY_STEREO_INSTANCING_ENABLED
#if !defined(UNITY_VERTEX_INPUT_INSTANCE_ID)
# define UNITY_VERTEX_INPUT_INSTANCE_ID DEFAULT_UNITY_VERTEX_INPUT_INSTANCE_ID
#endif
////////////////////////////////////////////////////////
// basic stereo instancing setups
// - UNITY_VERTEX_OUTPUT_STEREO Declare stereo target eye field in vertex shader output struct.
// - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO Assign the stereo target eye.
// - UNITY_TRANSFER_VERTEX_OUTPUT_STEREO Copy stero target from input struct to output struct. Used in vertex shader.
// - UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX
#ifdef UNITY_STEREO_INSTANCING_ENABLED
#if defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)
#define DEFAULT_UNITY_VERTEX_OUTPUT_STEREO uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex; uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
#define DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output) output.stereoTargetEyeIndexAsRTArrayIdx = unity_StereoEyeIndex; output.stereoTargetEyeIndexAsBlendIdx0 = unity_StereoEyeIndex;
#define DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output) output.stereoTargetEyeIndexAsBlendIdx0 = input.stereoTargetEyeIndexAsBlendIdx0;
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input) unity_StereoEyeIndex = input.stereoTargetEyeIndexAsBlendIdx0;
#elif defined(SHADER_API_PSSL) && defined(TESSELLATION_ON)
// Use of SV_RenderTargetArrayIndex is a little more complicated if we have tessellation stages involved
// This will add an extra instructions which we might be able to optimize away in some stages if we are careful.
#if defined(SHADER_STAGE_VERTEX)
#define DEFAULT_UNITY_VERTEX_OUTPUT_STEREO uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
#define DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output) output.stereoTargetEyeIndexAsBlendIdx0 = unity_StereoEyeIndex;
#define DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output) output.stereoTargetEyeIndexAsBlendIdx0 = input.stereoTargetEyeIndexAsBlendIdx0;
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input) unity_StereoEyeIndex = input.stereoTargetEyeIndexAsBlendIdx0;
#else
#define DEFAULT_UNITY_VERTEX_OUTPUT_STEREO uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex; uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
#define DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output) output.stereoTargetEyeIndexAsRTArrayIdx = unity_StereoEyeIndex; output.stereoTargetEyeIndexAsBlendIdx0 = unity_StereoEyeIndex;
#define DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output) output.stereoTargetEyeIndexAsBlendIdx0 = input.stereoTargetEyeIndexAsBlendIdx0;
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input) unity_StereoEyeIndex = input.stereoTargetEyeIndexAsBlendIdx0;
#endif
#else
#define DEFAULT_UNITY_VERTEX_OUTPUT_STEREO uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
#define DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output) output.stereoTargetEyeIndexAsRTArrayIdx = unity_StereoEyeIndex
#define DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output) output.stereoTargetEyeIndexAsRTArrayIdx = input.stereoTargetEyeIndexAsRTArrayIdx;
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input) unity_StereoEyeIndex = input.stereoTargetEyeIndexAsRTArrayIdx;
#endif
#elif defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#define DEFAULT_UNITY_VERTEX_OUTPUT_STEREO float stereoTargetEyeIndexAsBlendIdx0 : BLENDWEIGHT0;
// HACK: Workaround for Mali shader compiler issues with directly using GL_ViewID_OVR (GL_OVR_multiview). This array just contains the values 0 and 1.
#define DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output) output.stereoTargetEyeIndexAsBlendIdx0 = unity_StereoEyeIndices[unity_StereoEyeIndex].x;
#define DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output) output.stereoTargetEyeIndexAsBlendIdx0 = input.stereoTargetEyeIndexAsBlendIdx0;
#if defined(SHADER_STAGE_VERTEX)
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input)
#else
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input) unity_StereoEyeIndex = (uint) input.stereoTargetEyeIndexAsBlendIdx0;
#endif
#else
#define DEFAULT_UNITY_VERTEX_OUTPUT_STEREO
#define DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output)
#define DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output)
#define DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input)
#endif
#if !defined(UNITY_VERTEX_OUTPUT_STEREO)
# define UNITY_VERTEX_OUTPUT_STEREO DEFAULT_UNITY_VERTEX_OUTPUT_STEREO
#endif
#if !defined(UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO)
# define UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output) DEFAULT_UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output)
#endif
#if !defined(UNITY_TRANSFER_VERTEX_OUTPUT_STEREO)
# define UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output) DEFAULT_UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output)
#endif
#if !defined(UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX)
# define UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input) DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input)
#endif
////////////////////////////////////////////////////////
// - UNITY_SETUP_INSTANCE_ID Should be used at the very beginning of the vertex shader / fragment shader,
// so that succeeding code can have access to the global unity_InstanceID.
// Also procedural function is called to setup instance data.
// - UNITY_TRANSFER_INSTANCE_ID Copy instance ID from input struct to output struct. Used in vertex shader.
#if UNITY_ANY_INSTANCING_ENABLED
void UnitySetupInstanceID(uint inputInstanceID)
{
#ifdef UNITY_STEREO_INSTANCING_ENABLED
#if !defined(SHADEROPTIONS_XR_MAX_VIEWS) || SHADEROPTIONS_XR_MAX_VIEWS <= 2
#if defined(SHADER_API_GLES3)
// We must calculate the stereo eye index differently for GLES3
// because otherwise, the unity shader compiler will emit a bitfieldInsert function.
// bitfieldInsert requires support for glsl version 400 or later. Therefore the
// generated glsl code will fail to compile on lower end devices. By changing the
// way we calculate the stereo eye index, we can help the shader compiler to avoid
// emitting the bitfieldInsert function and thereby increase the number of devices we
// can run stereo instancing on.
unity_StereoEyeIndex = round(fmod(inputInstanceID, 2.0));
unity_InstanceID = unity_BaseInstanceID + (inputInstanceID >> 1);
#else
// stereo eye index is automatically figured out from the instance ID
unity_StereoEyeIndex = inputInstanceID & 0x01;
unity_InstanceID = unity_BaseInstanceID + (inputInstanceID >> 1);
#endif
#else
unity_StereoEyeIndex = inputInstanceID % _XRViewCount;
unity_InstanceID = unity_BaseInstanceID + (inputInstanceID / _XRViewCount);
#endif
#else
unity_InstanceID = inputInstanceID + unity_BaseInstanceID;
#endif
}
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
#ifndef UNITY_INSTANCING_PROCEDURAL_FUNC
#error "UNITY_INSTANCING_PROCEDURAL_FUNC must be defined."
#else
void UNITY_INSTANCING_PROCEDURAL_FUNC(); // forward declaration of the procedural function
#define DEFAULT_UNITY_SETUP_INSTANCE_ID(input) { UnitySetupInstanceID(UNITY_GET_INSTANCE_ID(input)); UNITY_INSTANCING_PROCEDURAL_FUNC();}
#endif
#else
#define DEFAULT_UNITY_SETUP_INSTANCE_ID(input) { UnitySetupInstanceID(UNITY_GET_INSTANCE_ID(input));}
#endif
#define UNITY_TRANSFER_INSTANCE_ID(input, output) output.instanceID = UNITY_GET_INSTANCE_ID(input)
#else
#define DEFAULT_UNITY_SETUP_INSTANCE_ID(input)
#define UNITY_TRANSFER_INSTANCE_ID(input, output)
#endif
#if !defined(UNITY_SETUP_INSTANCE_ID)
# define UNITY_SETUP_INSTANCE_ID(input) DEFAULT_UNITY_SETUP_INSTANCE_ID(input)
#endif
////////////////////////////////////////////////////////
// instanced property arrays
#if defined(UNITY_INSTANCING_ENABLED) || defined(UNITY_DOTS_INSTANCING_ENABLED)
#ifdef UNITY_FORCE_MAX_INSTANCE_COUNT
#define UNITY_INSTANCED_ARRAY_SIZE UNITY_FORCE_MAX_INSTANCE_COUNT
#elif defined(UNITY_INSTANCING_SUPPORT_FLEXIBLE_ARRAY_SIZE)
#define UNITY_INSTANCED_ARRAY_SIZE 2 // minimum array size that ensures dynamic indexing
#elif defined(UNITY_MAX_INSTANCE_COUNT)
#define UNITY_INSTANCED_ARRAY_SIZE UNITY_MAX_INSTANCE_COUNT
#else
#if (defined(SHADER_API_VULKAN) && defined(SHADER_API_MOBILE)) || defined(SHADER_API_SWITCH)
#define UNITY_INSTANCED_ARRAY_SIZE 250
#else
#define UNITY_INSTANCED_ARRAY_SIZE 500
#endif
#endif
#if defined(UNITY_DOTS_INSTANCING_ENABLED)
#define UNITY_INSTANCING_BUFFER_START(buf) UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(UnityInstancing_##buf)
#define UNITY_INSTANCING_BUFFER_END(arr) UNITY_INSTANCING_CBUFFER_SCOPE_END
#define UNITY_DEFINE_INSTANCED_PROP(type, var) type var;
#define UNITY_ACCESS_INSTANCED_PROP(arr, var) var
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityDOTSInstancing.hlsl"
#else
#define UNITY_INSTANCING_BUFFER_START(buf) UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(UnityInstancing_##buf) struct {
#define UNITY_INSTANCING_BUFFER_END(arr) } arr##Array[UNITY_INSTANCED_ARRAY_SIZE]; UNITY_INSTANCING_CBUFFER_SCOPE_END
#define UNITY_DEFINE_INSTANCED_PROP(type, var) type var;
#define UNITY_ACCESS_INSTANCED_PROP(arr, var) arr##Array[unity_InstanceID].var
#define UNITY_DOTS_INSTANCING_START(name)
#define UNITY_DOTS_INSTANCING_END(name)
#define UNITY_DOTS_INSTANCED_PROP(type, name)
#define UNITY_ACCESS_DOTS_INSTANCED_PROP(type, var) var
#define UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(type, metadata_underscore_var) This_macro_cannot_be_called_without_UNITY_DOTS_INSTANCING_ENABLED
#define UNITY_ACCESS_DOTS_AND_TRADITIONAL_INSTANCED_PROP(type, arr, var) UNITY_ACCESS_INSTANCED_PROP(arr, var)
#endif
// Put worldToObject array to a separate CB if UNITY_ASSUME_UNIFORM_SCALING is defined. Most of the time it will not be used.
#ifdef UNITY_ASSUME_UNIFORM_SCALING
#define UNITY_WORLDTOOBJECTARRAY_CB 1
#else
#define UNITY_WORLDTOOBJECTARRAY_CB 0
#endif
#if defined(UNITY_INSTANCED_LOD_FADE) && (defined(LOD_FADE_PERCENTAGE) || defined(LOD_FADE_CROSSFADE))
#define UNITY_USE_LODFADE_ARRAY
#endif
#if defined(UNITY_INSTANCED_RENDERING_LAYER)
#define UNITY_USE_RENDERINGLAYER_ARRAY
#endif
#ifdef UNITY_INSTANCED_LIGHTMAPSTS
#ifdef LIGHTMAP_ON
#define UNITY_USE_LIGHTMAPST_ARRAY
#endif
#ifdef DYNAMICLIGHTMAP_ON
#define UNITY_USE_DYNAMICLIGHTMAPST_ARRAY
#endif
#endif
#if defined(UNITY_INSTANCED_SH) && !defined(LIGHTMAP_ON)
#if !defined(DYNAMICLIGHTMAP_ON)
#define UNITY_USE_SHCOEFFS_ARRAYS
#endif
#if defined(SHADOWS_SHADOWMASK)
#define UNITY_USE_PROBESOCCLUSION_ARRAY
#endif
#endif
#if !defined(UNITY_DOTS_INSTANCING_ENABLED)
UNITY_INSTANCING_BUFFER_START(PerDraw0)
#ifndef UNITY_DONT_INSTANCE_OBJECT_MATRICES
UNITY_DEFINE_INSTANCED_PROP(float4x4, unity_ObjectToWorldArray)
#if UNITY_WORLDTOOBJECTARRAY_CB == 0
UNITY_DEFINE_INSTANCED_PROP(float4x4, unity_WorldToObjectArray)
#endif
#endif
#if defined(UNITY_USE_LODFADE_ARRAY) && defined(UNITY_INSTANCING_SUPPORT_FLEXIBLE_ARRAY_SIZE)
UNITY_DEFINE_INSTANCED_PROP(float2, unity_LODFadeArray)
#define unity_LODFade UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, unity_LODFadeArray).xyxx
#endif
#if defined(UNITY_USE_RENDERINGLAYER_ARRAY) && defined(UNITY_INSTANCING_SUPPORT_FLEXIBLE_ARRAY_SIZE)
UNITY_DEFINE_INSTANCED_PROP(float, unity_RenderingLayerArray)
#define unity_RenderingLayer UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, unity_RenderingLayerArray).xxxx
#endif
// TODO: Hybrid V1 compatibility, remove once Hybrid V1 is removed
#if defined(UNITY_HYBRID_V1_INSTANCING_ENABLED) && defined(HYBRID_V1_CUSTOM_ADDITIONAL_MATERIAL_VARS)
HYBRID_V1_CUSTOM_ADDITIONAL_MATERIAL_VARS
#endif
UNITY_INSTANCING_BUFFER_END(unity_Builtins0)
UNITY_INSTANCING_BUFFER_START(PerDraw1)
#if !defined(UNITY_DONT_INSTANCE_OBJECT_MATRICES) && UNITY_WORLDTOOBJECTARRAY_CB == 1
UNITY_DEFINE_INSTANCED_PROP(float4x4, unity_WorldToObjectArray)
#endif
#if defined(UNITY_USE_LODFADE_ARRAY) && !defined(UNITY_INSTANCING_SUPPORT_FLEXIBLE_ARRAY_SIZE)
UNITY_DEFINE_INSTANCED_PROP(float2, unity_LODFadeArray)
#define unity_LODFade UNITY_ACCESS_INSTANCED_PROP(unity_Builtins1, unity_LODFadeArray).xyxx
#endif
#if defined(UNITY_USE_RENDERINGLAYER_ARRAY) && !defined(UNITY_INSTANCING_SUPPORT_FLEXIBLE_ARRAY_SIZE)
UNITY_DEFINE_INSTANCED_PROP(float, unity_RenderingLayerArray)
#define unity_RenderingLayer UNITY_ACCESS_INSTANCED_PROP(unity_Builtins1, unity_RenderingLayerArray).xxxx
#endif
UNITY_INSTANCING_BUFFER_END(unity_Builtins1)
UNITY_INSTANCING_BUFFER_START(PerDraw2)
#ifdef UNITY_USE_LIGHTMAPST_ARRAY
UNITY_DEFINE_INSTANCED_PROP(float4, unity_LightmapSTArray)
UNITY_DEFINE_INSTANCED_PROP(float4, unity_LightmapIndexArray)
#define unity_LightmapST UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_LightmapSTArray)
#endif
#ifdef UNITY_USE_DYNAMICLIGHTMAPST_ARRAY
UNITY_DEFINE_INSTANCED_PROP(float4, unity_DynamicLightmapSTArray)
#define unity_DynamicLightmapST UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_DynamicLightmapSTArray)
#endif
#ifdef UNITY_USE_SHCOEFFS_ARRAYS
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHArArray)
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHAgArray)
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHAbArray)
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHBrArray)
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHBgArray)
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHBbArray)
UNITY_DEFINE_INSTANCED_PROP(half4, unity_SHCArray)
#define unity_SHAr UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHArArray)
#define unity_SHAg UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHAgArray)
#define unity_SHAb UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHAbArray)
#define unity_SHBr UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHBrArray)
#define unity_SHBg UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHBgArray)
#define unity_SHBb UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHBbArray)
#define unity_SHC UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_SHCArray)
#endif
#ifdef UNITY_USE_PROBESOCCLUSION_ARRAY
UNITY_DEFINE_INSTANCED_PROP(half4, unity_ProbesOcclusionArray)
#define unity_ProbesOcclusion UNITY_ACCESS_INSTANCED_PROP(unity_Builtins2, unity_ProbesOcclusionArray)
#endif
UNITY_INSTANCING_BUFFER_END(unity_Builtins2)
#endif
// TODO: What about UNITY_DONT_INSTANCE_OBJECT_MATRICES for DOTS?
#if defined(UNITY_DOTS_INSTANCING_ENABLED)
#undef UNITY_MATRIX_M
#undef UNITY_MATRIX_I_M
#ifdef MODIFY_MATRIX_FOR_CAMERA_RELATIVE_RENDERING
#define UNITY_MATRIX_M ApplyCameraTranslationToMatrix(LoadDOTSInstancedData_float4x4_from_float3x4(UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(float3x4, Metadata_unity_ObjectToWorld)))
#define UNITY_MATRIX_I_M ApplyCameraTranslationToInverseMatrix(LoadDOTSInstancedData_float4x4_from_float3x4(UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(float3x4, Metadata_unity_WorldToObject)))
#else
#define UNITY_MATRIX_M LoadDOTSInstancedData_float4x4_from_float3x4(UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(float3x4, Metadata_unity_ObjectToWorld))
#define UNITY_MATRIX_I_M LoadDOTSInstancedData_float4x4_from_float3x4(UNITY_DOTS_INSTANCED_METADATA_NAME_FROM_MACRO(float3x4, Metadata_unity_WorldToObject))
#endif
#else
#ifndef UNITY_DONT_INSTANCE_OBJECT_MATRICES
#undef UNITY_MATRIX_M
#undef UNITY_MATRIX_I_M
// Use #if instead of preprocessor concatenation to avoid really hard to debug
// preprocessing issues in some cases.
#if UNITY_WORLDTOOBJECTARRAY_CB == 0
#define UNITY_BUILTINS_WITH_WORLDTOOBJECTARRAY unity_Builtins0
#else
#define UNITY_BUILTINS_WITH_WORLDTOOBJECTARRAY unity_Builtins1
#endif
#ifdef MODIFY_MATRIX_FOR_CAMERA_RELATIVE_RENDERING
#define UNITY_MATRIX_M ApplyCameraTranslationToMatrix(UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, unity_ObjectToWorldArray))
#define UNITY_MATRIX_I_M ApplyCameraTranslationToInverseMatrix(UNITY_ACCESS_INSTANCED_PROP(UNITY_BUILTINS_WITH_WORLDTOOBJECTARRAY, unity_WorldToObjectArray))
#else
#define UNITY_MATRIX_M UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, unity_ObjectToWorldArray)
#define UNITY_MATRIX_I_M UNITY_ACCESS_INSTANCED_PROP(UNITY_BUILTINS_WITH_WORLDTOOBJECTARRAY, unity_WorldToObjectArray)
#endif
#endif
#endif
#else // UNITY_INSTANCING_ENABLED
// in procedural mode we don't need cbuffer, and properties are not uniforms
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
#define UNITY_INSTANCING_BUFFER_START(buf)
#define UNITY_INSTANCING_BUFFER_END(arr)
#define UNITY_DEFINE_INSTANCED_PROP(type, var) static type var;
#else
#define UNITY_INSTANCING_BUFFER_START(buf) CBUFFER_START(buf)
#define UNITY_INSTANCING_BUFFER_END(arr) CBUFFER_END
#define UNITY_DEFINE_INSTANCED_PROP(type, var) type var;
#endif
#define UNITY_ACCESS_INSTANCED_PROP(arr, var) var
#endif // UNITY_INSTANCING_ENABLED
#endif // UNITY_INSTANCING_INCLUDED

View File

@@ -0,0 +1,9 @@
// The old version number system below is deprecated whith Graphic Packages that have move as core package of Unity.
// User should rely on the Macro UNITY_VERSION now to detect which version of Unity is coupled to the current set of pipeline shader
// Example of usage #if UNITY_VERSION >= 202120 to check if the version is above or equal 2021.2
#define SHADER_LIBRARY_VERSION_MAJOR 11
#define SHADER_LIBRARY_VERSION_MINOR 0
#define VERSION_GREATER_EQUAL(major, minor) ((SHADER_LIBRARY_VERSION_MAJOR > major) || ((SHADER_LIBRARY_VERSION_MAJOR == major) && (SHADER_LIBRARY_VERSION_MINOR >= minor)))
#define VERSION_LOWER(major, minor) ((SHADER_LIBRARY_VERSION_MAJOR < major) || ((SHADER_LIBRARY_VERSION_MAJOR == major) && (SHADER_LIBRARY_VERSION_MINOR < minor)))
#define VERSION_EQUAL(major, minor) ((SHADER_LIBRARY_VERSION_MAJOR == major) && (SHADER_LIBRARY_VERSION_MINOR == minor))

View File

@@ -0,0 +1,211 @@
#include "GraniteShaderLibBase.hlsl"
#define VtAddressMode_Wrap 0
#define VtAddressMode_Clamp 1
#define VtAddressMode_Udim 2
#define VtFilter_Anisotropic 0
#define VtLevel_Automatic 0
#define VtLevel_Lod 1
#define VtLevel_Bias 2
#define VtLevel_Derivatives 3
#define VtUvSpace_Regular 0
#define VtUvSpace_PreTransformed 1
#define VtSampleQuality_Low 0
#define VtSampleQuality_High 1
struct VtInputParameters
{
float2 uv;
float lodOrOffset;
float2 dx;
float2 dy;
int addressMode;
int filterMode;
int levelMode;
int uvMode;
int sampleQuality;
};
int VirtualTexturingLookup(
in GraniteConstantBuffers grCB,
in GraniteTranslationTexture translationTable,
in VtInputParameters input,
out GraniteLookupData graniteLookupData,
out float4 resolveResult
)
{
GraniteStreamingTextureConstantBuffer grSTCB = grCB.streamingTextureBuffer;
GraniteTilesetConstantBuffer tsCB = grCB.tilesetBuffer;
float2 texCoord = input.uv;
float2 dx;
float2 dy;
float mipLevel; //interger
if (input.levelMode == VtLevel_Automatic)
{
dx = ddx(texCoord);
dy = ddy(texCoord);
}
else if (input.levelMode == VtLevel_Bias)
{
// We can't simply add the bias after the mip-calculation since the derivatives
// are also used when sampling the cache so make sure we apply bias by scaling derivatives
if ( input.sampleQuality == VtSampleQuality_High )
{
float offsetPow2 = pow(2.0f, input.lodOrOffset);
dx = ddx(texCoord) * offsetPow2;
dy = ddy(texCoord) * offsetPow2;
}
// In low qauality we don't care about cache derivatives and will add the bias later
else
{
dx = ddx(texCoord);
dy = ddy(texCoord);
}
}
else if (input.levelMode == VtLevel_Derivatives)
{
dx = input.dx;
dy = input.dy;
}
else /*input.levelMode == VtLevel_Lod*/
{
//gra_TrilinearOffset ensures we do round-nearest for no-trilinear and
//round-floor for trilinear.
float clampedLevel = clamp(input.lodOrOffset + gra_TrilinearOffset, 0.0f, gra_NumLevels);
mipLevel = floor(clampedLevel);
dx = float2(frac(clampedLevel), 0.0f); // trilinear blend ratio
dy = float2(0.0f,0.0f);
}
// Transform the derivatives to atlas space if needed
if (input.uvMode == VtUvSpace_Regular && input.levelMode != VtLevel_Lod)
{
dx = gra_Transform.zw * dx;
dy = gra_Transform.zw * dy;
}
if (input.levelMode != VtLevel_Lod)
{
mipLevel = GranitePrivate_CalcMiplevelAnisotropic(grCB.tilesetBuffer, grCB.streamingTextureBuffer, dx, dy);
// Simply add it here derivatives are wrong from this point onwards but not used anymore
if ( input.sampleQuality == VtSampleQuality_Low && input.levelMode == VtLevel_Bias)
{
mipLevel += input.lodOrOffset;
// GranitePrivate_CalcMiplevelAnisotropic will already clamp between 0 gra_NumLevels
// But we need to do it again here. The alternative is modifying dx,dy before passing to
// GranitePrivate_CalcMiplevelAnisotropic adding a pow2 + 4 fmuls so probably
// the exra clamp is more appropriate here.
mipLevel = clamp(mipLevel, 0.0f, gra_NumLevels);
}
mipLevel = floor(mipLevel + 0.5f); //round nearest
}
// Apply clamp/wrap mode if needed and transform into atlas space
// If the user passes in pre-transformed texture coords clamping and wrapping should be handled by the user
if (input.uvMode == VtUvSpace_Regular)
{
if (input.addressMode == VtAddressMode_Wrap)
{
texCoord = frac(input.uv);
}
else if (input.addressMode == VtAddressMode_Clamp)
{
float2 epsilon2 = float2(gra_AssetWidthRcp, gra_AssetHeightRcp);
texCoord = clamp(input.uv, epsilon2, float2(1,1) - epsilon2);
}
else if (input.addressMode == VtAddressMode_Udim)
{
// not modified (i.e outside of the 0-1 range, atlas transform below will take care of it)
texCoord = input.uv;
}
texCoord = Granite_Transform(gra_StreamingTextureCB, texCoord);
}
// calculate resolver data
float2 level0NumTiles = float2(gra_Level0NumTilesX, gra_Level0NumTilesX*gra_NumTilesYScale);
float2 virtualTilesUv = floor(texCoord * level0NumTiles * pow(0.5, mipLevel));
resolveResult = GranitePrivate_MakeResolveOutput(tsCB, virtualTilesUv, mipLevel);
float4 translationTableData;
if (input.levelMode != VtLevel_Lod)
{
// Look up the physical page indexes and the number of pages on the mipmap
// level of the page in the translation texture
// Note: this is equal for both anisotropic and linear sampling
// We could use a sample bias here for 'auto' mip level detection
#if (GRA_LOAD_INSTR==0)
translationTableData = GranitePrivate_SampleLevel_Translation(translationTable, texCoord, mipLevel);
#else
translationTableData = GranitePrivate_Load(translationTable, gra_Int3(virtualTilesUv, mipLevel));
#endif
}
else
{
// Look up the physical page indexes and the number of pages on the mipmap
// level of the page in the translation texture
// Note: this is equal for both anisotropic and linear sampling
// We could use a sample bias here for 'auto' mip level detection
#if (GRA_LOAD_INSTR==0)
translationTableData = GranitePrivate_SampleLevel_Translation(translationTable, texCoord, mipLevel);
#else
translationTableData = GranitePrivate_Load(translationTable, gra_Int3(virtualTilesUv, mipLevel));
#endif
}
graniteLookupData.translationTableData = translationTableData;
graniteLookupData.textureCoordinates = texCoord;
graniteLookupData.dX = dx;
graniteLookupData.dY = dy;
return 1;
}
int VirtualTexturingSample(
in GraniteTilesetConstantBuffer tsCB,
in GraniteLookupData graniteLookupData,
in GraniteCacheTexture cacheTexture,
in int layer,
in int levelMode,
in int quality,
out float4 result)
{
// Convert from pixels to [0-1] and look up in the physical page texture
float2 deltaScale;
float3 cacheCoord = GranitePrivate_TranslateCoord(tsCB, graniteLookupData.textureCoordinates, graniteLookupData.translationTableData, layer, deltaScale);
if ( levelMode != VtLevel_Lod )
{
if ( quality == VtSampleQuality_Low )
{
// This leads to small artefacts at tile borders but is generally not noticable unless the texture
// is greatly magnified
result = GranitePrivate_SampleArray(cacheTexture, cacheCoord);
}
else /* quality == VtSampleQuality_High */
{
deltaScale *= gra_LodBiasPow2;
// Calculate the delta scale this works by first converting the [0-1] texcoord deltas to
// pixel deltas on the current mip level, then dividing by the cache size to convert to [0-1] cache deltas
float2 sampDeltaX = graniteLookupData.dX*deltaScale;
float2 sampDeltaY = graniteLookupData.dY*deltaScale;
result = GranitePrivate_SampleGradArray(cacheTexture, cacheCoord, sampDeltaX, sampDeltaY);
}
}
else
{
result = GranitePrivate_SampleLevelArray(cacheTexture, cacheCoord, graniteLookupData.dX.x);
}
return 1;
}

View File

@@ -0,0 +1,380 @@
#ifndef UNITY_VOLUME_RENDERING_INCLUDED
#define UNITY_VOLUME_RENDERING_INCLUDED
// Reminder:
// OpticalDepth(x, y) = Integral{x, y}{Extinction(t) dt}
// Transmittance(x, y) = Exp(-OpticalDepth(x, y))
// Transmittance(x, z) = Transmittance(x, y) * Transmittance(y, z)
// Integral{a, b}{Transmittance(0, t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) dt}
real TransmittanceFromOpticalDepth(real opticalDepth)
{
return exp(-opticalDepth);
}
real3 TransmittanceFromOpticalDepth(real3 opticalDepth)
{
return exp(-opticalDepth);
}
real OpacityFromOpticalDepth(real opticalDepth)
{
return 1 - TransmittanceFromOpticalDepth(opticalDepth);
}
real3 OpacityFromOpticalDepth(real3 opticalDepth)
{
return 1 - TransmittanceFromOpticalDepth(opticalDepth);
}
real OpticalDepthFromOpacity(real opacity)
{
return -log(1 - opacity);
}
real3 OpticalDepthFromOpacity(real3 opacity)
{
return -log(1 - opacity);
}
//
// ---------------------------------- Deep Pixel Compositing ---------------------------------------
//
// TODO: it would be good to improve the perf and numerical stability
// of approximations below by finding a polynomial approximation.
// input = {radiance, opacity}
// Note that opacity must be less than 1 (not fully opaque).
real4 LinearizeRGBA(real4 value)
{
// See "Deep Compositing Using Lie Algebras".
// log(A) = {OpticalDepthFromOpacity(A.a) / A.a * A.rgb, -OpticalDepthFromOpacity(A.a)}.
// We drop redundant negations.
real a = value.a;
real d = -log(1 - a);
real r = (a >= REAL_EPS) ? (d * rcp(a)) : 1; // Prevent numerical explosion
return real4(r * value.rgb, d);
}
// input = {radiance, optical_depth}
// Note that opacity must be less than 1 (not fully opaque).
real4 LinearizeRGBD(real4 value)
{
// See "Deep Compositing Using Lie Algebras".
// log(A) = {A.a / OpacityFromOpticalDepth(A.a) * A.rgb, -A.a}.
// We drop redundant negations.
real d = value.a;
real a = 1 - exp(-d);
real r = (a >= REAL_EPS) ? (d * rcp(a)) : 1; // Prevent numerical explosion
return real4(r * value.rgb, d);
}
// output = {radiance, opacity}
// Note that opacity must be less than 1 (not fully opaque).
real4 DelinearizeRGBA(real4 value)
{
// See "Deep Compositing Using Lie Algebras".
// exp(B) = {OpacityFromOpticalDepth(-B.a) / -B.a * B.rgb, OpacityFromOpticalDepth(-B.a)}.
// We drop redundant negations.
real d = value.a;
real a = 1 - exp(-d);
real i = (a >= REAL_EPS) ? (a * rcp(d)) : 1; // Prevent numerical explosion
return real4(i * value.rgb, a);
}
// input = {radiance, optical_depth}
// Note that opacity must be less than 1 (not fully opaque).
real4 DelinearizeRGBD(real4 value)
{
// See "Deep Compositing Using Lie Algebras".
// exp(B) = {OpacityFromOpticalDepth(-B.a) / -B.a * B.rgb, -B.a}.
// We drop redundant negations.
real d = value.a;
real a = 1 - exp(-d);
real i = (a >= REAL_EPS) ? (a * rcp(d)) : 1; // Prevent numerical explosion
return real4(i * value.rgb, d);
}
//
// ----------------------------- Homogeneous Participating Media -----------------------------------
//
real OpticalDepthHomogeneousMedium(real extinction, real intervalLength)
{
return extinction * intervalLength;
}
real TransmittanceHomogeneousMedium(real extinction, real intervalLength)
{
return TransmittanceFromOpticalDepth(OpticalDepthHomogeneousMedium(extinction, intervalLength));
}
// Integral{a, b}{TransmittanceHomogeneousMedium(k, t - a) dt}.
real TransmittanceIntegralHomogeneousMedium(real extinction, real intervalLength)
{
// Note: when multiplied by the extinction coefficient, it becomes
// Albedo * (1 - TransmittanceFromOpticalDepth(d)) = Albedo * Opacity(d).
return rcp(extinction) - rcp(extinction) * exp(-extinction * intervalLength);
}
//
// ----------------------------------- Height Fog --------------------------------------------------
//
// Can be used to scale base extinction and scattering coefficients.
real ComputeHeightFogMultiplier(real height, real baseHeight, real2 heightExponents)
{
real h = max(height - baseHeight, 0);
real rcpH = heightExponents.x;
return exp(-h * rcpH);
}
// Optical depth between two endpoints.
real OpticalDepthHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
real cosZenith, real startHeight, real intervalLength)
{
// Height fog is composed of two slices of optical depth:
// - homogeneous fog below 'baseHeight': d = k * t
// - exponential fog above 'baseHeight': d = Integrate[k * e^(-(h + z * x) / H) dx, {x, 0, t}]
real H = heightExponents.y;
real rcpH = heightExponents.x;
real Z = cosZenith;
real absZ = max(abs(cosZenith), REAL_EPS);
real rcpAbsZ = rcp(absZ);
real endHeight = startHeight + intervalLength * Z;
real minHeight = min(startHeight, endHeight);
real h = max(minHeight - baseHeight, 0);
real homFogDist = clamp((baseHeight - minHeight) * rcpAbsZ, 0, intervalLength);
real expFogDist = intervalLength - homFogDist;
real expFogMult = exp(-h * rcpH) * (1 - exp(-expFogDist * absZ * rcpH)) * (rcpAbsZ * H);
return baseExtinction * (homFogDist + expFogMult);
}
// This version of the function assumes the interval of infinite length.
real OpticalDepthHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
real cosZenith, real startHeight)
{
real H = heightExponents.y;
real rcpH = heightExponents.x;
real Z = cosZenith;
real absZ = max(abs(cosZenith), REAL_EPS);
real rcpAbsZ = rcp(absZ);
real minHeight = (Z >= 0) ? startHeight : -rcp(REAL_EPS);
real h = max(minHeight - baseHeight, 0);
real homFogDist = max((baseHeight - minHeight) * rcpAbsZ, 0);
real expFogMult = exp(-h * rcpH) * (rcpAbsZ * H);
return baseExtinction * (homFogDist + expFogMult);
}
real TransmittanceHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
real cosZenith, real startHeight, real intervalLength)
{
real od = OpticalDepthHeightFog(baseExtinction, baseHeight, heightExponents,
cosZenith, startHeight, intervalLength);
return TransmittanceFromOpticalDepth(od);
}
real TransmittanceHeightFog(real baseExtinction, real baseHeight, real2 heightExponents,
real cosZenith, real startHeight)
{
real od = OpticalDepthHeightFog(baseExtinction, baseHeight, heightExponents,
cosZenith, startHeight);
return TransmittanceFromOpticalDepth(od);
}
//
// ----------------------------------- Phase Functions ---------------------------------------------
//
real IsotropicPhaseFunction()
{
return INV_FOUR_PI;
}
real RayleighPhaseFunction(real cosTheta)
{
real k = 3 / (16 * PI);
return k * (1 + cosTheta * cosTheta);
}
real HenyeyGreensteinPhasePartConstant(real anisotropy)
{
real g = anisotropy;
return INV_FOUR_PI * (1 - g * g);
}
real HenyeyGreensteinPhasePartVarying(real anisotropy, real cosTheta)
{
real g = anisotropy;
real x = 1 + g * g - 2 * g * cosTheta;
real f = rsqrt(max(x, REAL_EPS)); // x^(-1/2)
return f * f * f; // x^(-3/2)
}
real HenyeyGreensteinPhaseFunction(real anisotropy, real cosTheta)
{
return HenyeyGreensteinPhasePartConstant(anisotropy) *
HenyeyGreensteinPhasePartVarying(anisotropy, cosTheta);
}
real CornetteShanksPhasePartConstant(real anisotropy)
{
real g = anisotropy;
return (3 / (8 * PI)) * (1 - g * g) / (2 + g * g);
}
// Similar to the RayleighPhaseFunction.
real CornetteShanksPhasePartSymmetrical(real cosTheta)
{
real h = 1 + cosTheta * cosTheta;
return h;
}
real CornetteShanksPhasePartAsymmetrical(real anisotropy, real cosTheta)
{
real g = anisotropy;
real x = 1 + g * g - 2 * g * cosTheta;
real f = rsqrt(max(x, REAL_EPS)); // x^(-1/2)
return f * f * f; // x^(-3/2)
}
real CornetteShanksPhasePartVarying(real anisotropy, real cosTheta)
{
return CornetteShanksPhasePartSymmetrical(cosTheta) *
CornetteShanksPhasePartAsymmetrical(anisotropy, cosTheta); // h * x^(-3/2)
}
// A better approximation of the Mie phase function.
// Ref: Henyey-Greenstein and Mie phase functions in Monte Carlo radiative transfer computations
real CornetteShanksPhaseFunction(real anisotropy, real cosTheta)
{
return CornetteShanksPhasePartConstant(anisotropy) *
CornetteShanksPhasePartVarying(anisotropy, cosTheta);
}
//
// --------------------------------- Importance Sampling -------------------------------------------
//
// Samples the interval of homogeneous participating medium using the closed-form tracking approach
// (proportionally to the transmittance).
// Returns the offset from the start of the interval and the weight = (transmittance / pdf).
// Ref: Monte Carlo Methods for Volumetric Light Transport Simulation, p. 5.
void ImportanceSampleHomogeneousMedium(real rndVal, real extinction, real intervalLength,
out real offset, out real weight)
{
// pdf = extinction * exp(extinction * (intervalLength - t)) / (exp(intervalLength * extinction) - 1)
// pdf = extinction * exp(-extinction * t) / (1 - exp(-extinction * intervalLength))
// weight = TransmittanceFromOpticalDepth(t) / pdf
// weight = exp(-extinction * t) / pdf
// weight = (1 - exp(-extinction * intervalLength)) / extinction
// weight = OpacityFromOpticalDepth(extinction * intervalLength) / extinction
real x = 1 - exp(-extinction * intervalLength);
real c = rcp(extinction);
// TODO: return 'rcpPdf' to support imperfect importance sampling...
weight = x * c;
offset = -log(1 - rndVal * x) * c;
}
void ImportanceSampleExponentialMedium(real rndVal, real extinction, real falloff,
out real offset, out real rcpPdf)
{
// Extinction[t] = Extinction[0] * exp(-falloff * t).
real c = extinction;
real a = falloff;
// TODO: optimize...
offset = -log(1 - a / c * log(rndVal)) / a;
rcpPdf = rcp(c * exp(-a * offset) * exp(-c / a * (1 - exp(-a * offset))));
}
// Implements equiangular light sampling.
// Returns the distance from the origin of the ray, the squared distance from the light,
// and the reciprocal of the PDF.
// Ref: Importance Sampling of Area Lights in Participating Medium.
void ImportanceSamplePunctualLight(real rndVal, real3 lightPosition, real lightSqRadius,
real3 rayOrigin, real3 rayDirection,
real tMin, real tMax,
out real t, out real sqDist, out real rcpPdf)
{
real3 originToLight = lightPosition - rayOrigin;
real originToLightProjDist = dot(originToLight, rayDirection);
real originToLightSqDist = dot(originToLight, originToLight);
real rayToLightSqDist = originToLightSqDist - originToLightProjDist * originToLightProjDist;
// Virtually offset the light to modify the PDF distribution.
real sqD = max(rayToLightSqDist + lightSqRadius, REAL_EPS);
real rcpD = rsqrt(sqD);
real d = sqD * rcpD;
real a = tMin - originToLightProjDist;
real b = tMax - originToLightProjDist;
real x = a * rcpD;
real y = b * rcpD;
#if 0
real theta0 = FastATan(x);
real theta1 = FastATan(y);
real gamma = theta1 - theta0;
real tanTheta = tan(theta0 + rndVal * gamma);
#else
// Same but faster:
// atan(y) - atan(x) = atan((y - x) / (1 + x * y))
// tan(atan(x) + z) = (x * cos(z) + sin(z)) / (cos(z) - x * sin(z))
// Both the tangent and the angle cannot be negative.
real tanGamma = abs((y - x) * rcp(max(0, 1 + x * y)));
real gamma = FastATanPos(tanGamma);
real z = rndVal * gamma;
real numer = x * cos(z) + sin(z);
real denom = cos(z) - x * sin(z);
real tanTheta = numer * rcp(denom);
#endif
real tRelative = d * tanTheta;
sqDist = sqD + tRelative * tRelative;
rcpPdf = gamma * rcpD * sqDist;
t = originToLightProjDist + tRelative;
// Remove the virtual light offset to obtain the real geometric distance.
sqDist = max(sqDist - lightSqRadius, REAL_EPS);
}
// Returns the cosine.
// Weight = Phase / Pdf = 1.
real ImportanceSampleRayleighPhase(real rndVal)
{
// real a = sqrt(16 * (rndVal - 1) * rndVal + 5);
// real b = -4 * rndVal + a + 2;
// real c = PositivePow(b, 0.33333333);
// return rcp(c) - c;
// Approximate...
return lerp(cos(PI * rndVal + PI), 2 * rndVal - 1, 0.5);
}
//
// ------------------------------------ Miscellaneous ----------------------------------------------
//
// Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
real3 TransmittanceColorAtDistanceToAbsorption(real3 transmittanceColor, real atDistance)
{
return -log(transmittanceColor + REAL_EPS) / max(atDistance, REAL_EPS);
}
#endif // UNITY_VOLUME_RENDERING_INCLUDED