A game about forced loneliness, made by TACStudios
at master 411 lines 15 kB view raw
1#ifndef PROBEVOLUMEDEBUG_BASE_HLSL 2#define PROBEVOLUMEDEBUG_BASE_HLSL 3 4// TEMPORARY WORKAROUND 5// Unfortunately we don't have a cross pipeline way to pass per frame constant. 6// One of the reason is that we don't want to force a certain Constant Buffer layout on users (read: SRP writer) for shared data. 7// This means that usually SRP Core functions (see SpaceTransforms.hlsl for example) use common names that are NOT declared in the Core package but rather in each pipelines. 8// The consequence is that when writing core shaders that need those variables, we currently have to copy their declaration and set them manually from core C# code to the relevant shaders. 9 10// Here is current the subset of variables and functions required by APV debug. 11// Copying them here means that these shaders don't support either XR or Camera Relative rendering (at least until those concept become fully cross pipeline) 12CBUFFER_START(ShaderVariablesProbeVolumeDebug) 13float4x4 unity_MatrixVP; // Sent by builtin 14float4x4 unity_MatrixInvV; // Sent by builtin 15float4x4 unity_ObjectToWorld; // Sent by builtin 16float4x4 unity_MatrixV; // Sent by builtin 17float4 _ScreenSize; 18float3 _WorldSpaceCameraPos; // Sent by builtin 19CBUFFER_END 20 21TEXTURE2D(_ExposureTexture); 22 23#define UNITY_MATRIX_VP unity_MatrixVP 24#define UNITY_MATRIX_V unity_MatrixV 25#define UNITY_MATRIX_I_V unity_MatrixInvV 26#define UNITY_MATRIX_M unity_ObjectToWorld 27 28float3 GetCurrentViewPosition() 29{ 30 return UNITY_MATRIX_I_V._14_24_34; 31} 32 33float GetCurrentExposureMultiplier() 34{ 35 return LOAD_TEXTURE2D(_ExposureTexture, int2(0, 0)).x; 36} 37 38#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" 39#include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/DecodeSH.hlsl" 40#include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl" 41#include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs.hlsl" 42 43 44uniform int _ShadingMode; 45uniform float _ExposureCompensation; 46uniform float _ProbeSize; 47uniform float4 _Color; 48uniform int _SubdivLevel; 49uniform float _CullDistance; 50uniform int _MaxAllowedSubdiv; 51uniform int _MinAllowedSubdiv; 52uniform float _ValidityThreshold; 53uniform uint _RenderingLayerMask; 54uniform float _OffsetSize; 55 56// Sampling Position Debug 57uniform bool _DebugProbeVolumeSampling = false; 58StructuredBuffer<float4> _positionNormalBuffer; 59uniform float4 _DebugArrowColor; // arrow color for position and normal debug 60uniform float4 _DebugLocator01Color; // locator color for final sampling position debug 61uniform float4 _DebugLocator02Color; // locator color for normal and view bias sampling position debug 62uniform float4 _DebugEmptyProbeData; // probe color for missing data 63uniform bool _ForceDebugNormalViewBias; // additional locator to debug Normal Bias and View Bias without AntiLeak Reduction Mode 64uniform bool _DebugSamplingNoise = false; 65uniform sampler2D _NumbersTex; 66 67UNITY_INSTANCING_BUFFER_START(Props) 68 UNITY_DEFINE_INSTANCED_PROP(float, _Validity) 69 UNITY_DEFINE_INSTANCED_PROP(float, _RenderingLayer) 70 UNITY_DEFINE_INSTANCED_PROP(float, _DilationThreshold) 71 UNITY_DEFINE_INSTANCED_PROP(float, _TouchupedByVolume) 72 UNITY_DEFINE_INSTANCED_PROP(float4, _IndexInAtlas) 73 UNITY_DEFINE_INSTANCED_PROP(float4, _Offset) 74 UNITY_DEFINE_INSTANCED_PROP(float, _RelativeSize) 75UNITY_INSTANCING_BUFFER_END(Props) 76 77struct appdata 78{ 79 float4 vertex : POSITION; 80 float3 normal : NORMAL; 81 float4 color : COLOR0; 82 float2 texCoord : TEXCOORD0; 83 UNITY_VERTEX_INPUT_INSTANCE_ID 84}; 85 86struct v2f 87{ 88 float4 vertex : SV_POSITION; 89 float3 normal : TEXCOORD1; 90 float4 color : COLOR0; 91 float2 texCoord : TEXCOORD0; 92 float2 samplingFactor_ValidityWeight : TEXCOORD2; // stores sampling factor (for Probe Sampling Debug view) and validity weight 93 float2 centerCoordSS : TEXCOORD3; 94 UNITY_VERTEX_INPUT_INSTANCE_ID 95}; 96 97void DoCull(inout v2f o) 98{ 99 ZERO_INITIALIZE(v2f, o); 100 o.samplingFactor_ValidityWeight = float2(0.0f, 1.0f); 101} 102 103// snappedProbePosition_WS : worldspace position of main probe (a corner of the 8 probes cube) 104// samplingPosition_WS : worldspace sampling position after applying 'NormalBias' and 'ViewBias' and 'ValidityAndNormalBased Leak Reduction' 105// normalizedOffset : normalized offset between sampling position and snappedProbePosition 106void FindSamplingData(float3 posWS, float3 normalWS, uint renderingLayer, out float3 snappedProbePosition_WS, out float3 samplingPositionNoAntiLeak_WS, out float probeDistance, out float3 normalizedOffset, out float validityWeights[8]) 107{ 108 float3 cameraPosition_WS = _WorldSpaceCameraPos; 109 float3 viewDir_WS = normalize(cameraPosition_WS - posWS); 110 111 if (_DebugSamplingNoise) 112 { 113 float2 posNDC = ComputeNormalizedDeviceCoordinates(posWS, UNITY_MATRIX_VP); 114 float2 posSS = floor(posNDC.xy * _ScreenSize.xy); 115 posWS = AddNoiseToSamplingPosition(posWS, posSS, viewDir_WS); 116 } 117 118 posWS -= _APVWorldOffset; 119 120 // uvw 121 APVResources apvRes = FillAPVResources(); 122 float3 uvw; 123 uint subdiv; 124 float3 biasedPosWS; 125 bool valid = TryToGetPoolUVWAndSubdiv(apvRes, posWS, normalWS, viewDir_WS, uvw, subdiv, biasedPosWS); 126 127 // Validity mask 128 float3 texCoord = uvw * _APVPoolDim - .5f; 129 float3 texFrac = frac(texCoord); 130 uint validityMask = LoadValidityMask(apvRes, renderingLayer, texCoord); 131 for (uint i = 0; i < 8; i++) 132 { 133 int3 probeCoord = GetSampleOffset(i); 134 float validityWeight = ((probeCoord.x == 1) ? texFrac.x : 1.0f - texFrac.x) * 135 ((probeCoord.y == 1) ? texFrac.y : 1.0f - texFrac.y) * 136 ((probeCoord.z == 1) ? texFrac.z : 1.0f - texFrac.z); 137 validityWeights[i] = validityWeight * GetValidityWeight(i, validityMask); 138 } 139 140 // Sample position 141 normalizedOffset = texFrac; 142 if (_APVLeakReductionMode == APVLEAKREDUCTIONMODE_PERFORMANCE) 143 { 144 float3 warped = uvw; 145 WarpUVWLeakReduction(apvRes, renderingLayer, warped); 146 normalizedOffset += (warped - uvw) * _APVPoolDim; 147 } 148 149 // stuff 150 probeDistance = ProbeDistance(subdiv); 151 snappedProbePosition_WS = GetSnappedProbePosition(biasedPosWS, subdiv) + _APVWorldOffset; 152 samplingPositionNoAntiLeak_WS = biasedPosWS + _APVWorldOffset; 153} 154 155// Return probe sampling weight 156float ComputeSamplingFactor(float3 probePosition_WS, float3 snappedProbePosition_WS, float3 normalizedOffset, float probeDistance) 157{ 158 float samplingFactor = -1.0f; 159 160 if (distance(snappedProbePosition_WS, probePosition_WS) < 0.0001f) 161 { 162 samplingFactor = (1.0f-normalizedOffset.x) * (1.0f-normalizedOffset.y) * (1.0f-normalizedOffset.z); 163 } 164 165 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(-1.0f, 0.0f, 0.0f)*probeDistance) < 0.0001f) 166 { 167 samplingFactor = (normalizedOffset.x) * (1.0f-normalizedOffset.y) * (1.0f-normalizedOffset.z); 168 } 169 170 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(-1.0f, -1.0f, 0.0f)*probeDistance) < 0.0001f) 171 { 172 samplingFactor = (normalizedOffset.x) * (normalizedOffset.y) * (1.0f-normalizedOffset.z); 173 } 174 175 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(0.0f, -1.0f, 0.0f)*probeDistance) < 0.0001f) 176 { 177 samplingFactor = (1.0f-normalizedOffset.x) * (normalizedOffset.y) * (1.0f-normalizedOffset.z); 178 } 179 180 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(-1.0f, 0.0f, -1.0f)*probeDistance) < 0.0001f) 181 { 182 samplingFactor = (normalizedOffset.x) * (1.0f-normalizedOffset.y) * (normalizedOffset.z); 183 } 184 185 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(0.0f, 0.0f, -1.0f)*probeDistance) < 0.0001f) 186 { 187 samplingFactor = (1.0f-normalizedOffset.x) * (1.0f-normalizedOffset.y) * (normalizedOffset.z); 188 } 189 190 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(-1.0f, -1.0f, -1.0f)*probeDistance) < 0.0001f) 191 { 192 samplingFactor = (normalizedOffset.x) * (normalizedOffset.y) * (normalizedOffset.z); 193 } 194 195 else if (distance(snappedProbePosition_WS, probePosition_WS + float3(0.0f, -1.0f, -1.0f)*probeDistance) < 0.0001f) 196 { 197 samplingFactor = (1.0f-normalizedOffset.x) * (normalizedOffset.y) * (normalizedOffset.z); 198 } 199 200 return samplingFactor; 201} 202 203// Sample a texture with numbers at the right place depending on a number input 204half4 SampleCharacter(int input, float2 texCoord) // Samples _NumbersTex to get given character 205{ 206 // texture is divided in 16 parts and contains following characters : '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.' (+ empty space) 207 float2 uv = float2((texCoord.x + input) / 16.0f, texCoord.y); 208 half4 color = tex2D(_NumbersTex, uv); 209 return color; 210} 211 212// Writes a floating number with two decimals using a texture with numbers. 213// Use to debug probe sampling weights with text 214half4 WriteFractNumber(float input, float2 texCoord) 215{ 216 // using 4 characters 217 float i = 4.0f; 218 219 // 0.00X 220 int n3_value = floor(frac(input * 100.0f) * 10.0f); 221 int n2_add = 0; 222 if (n3_value >= 5) {n2_add = 1;} 223 224 // 0.0X 225 int n2_value = floor(frac(input * 10.0f) * 10.0f); 226 n2_value += n2_add; 227 int n1_add = 0; 228 if (n2_value >= 10) {n2_value -= 10; n1_add = 1;} 229 230 // 0.X 231 int n1_value = floor(frac(input) * 10.0f); 232 n1_value += n1_add; 233 int n0_add = 0; 234 if (n1_value >= 10) {n1_value -= 10; n0_add = 1;} 235 236 // X 237 int n0_value = floor(input); 238 n0_value += n0_add; 239 240 float2 n0_uv = float2(clamp(texCoord.x*i - 0.0f, 0.0f, 1.0f), texCoord.y); 241 float2 dot_uv = float2(clamp(texCoord.x*i - 1.0f, 0.0f, 1.0f), texCoord.y); 242 float2 n1_uv = float2(clamp(texCoord.x*i - 2.0f, 0.0f, 1.0f), texCoord.y); 243 float2 n2_uv = float2(clamp(texCoord.x*i - 3.0f, 0.0f, 1.0f), texCoord.y); 244 245 half4 outVal = 0; 246 if (texCoord.x <= 0.25) 247 outVal = SampleCharacter(n0_value, n0_uv); 248 else if (texCoord.x <= 0.50) 249 outVal = SampleCharacter(10, dot_uv); 250 else if (texCoord.x <= 0.75) 251 outVal = SampleCharacter(n1_value, n1_uv); 252 else 253 outVal = SampleCharacter(n2_value, n2_uv); 254 255 return outVal; 256} 257 258 259 260// Finer culling, degenerate the vertices of the debug element if it lies over the max distance. 261// Coarser culling has already happened on CPU. 262bool ShouldCull(inout v2f o) 263{ 264 float4 position = float4(UNITY_MATRIX_M._m03_m13_m23, 1); 265 int brickSize = UNITY_ACCESS_INSTANCED_PROP(Props, _IndexInAtlas).w; 266 267 bool shouldCull = false; 268 if (distance(position.xyz + _APVWorldOffset, GetCurrentViewPosition()) > _CullDistance || brickSize > _MaxAllowedSubdiv || brickSize < _MinAllowedSubdiv) 269 { 270 DoCull(o); 271 shouldCull = true; 272 } 273 274 return shouldCull; 275} 276 277float3 EvalL1(float3 L0, float3 L1_R, float3 L1_G, float3 L1_B, float3 N) 278{ 279 float3 outLighting = 0; 280 L1_R = DecodeSH(L0.r, L1_R); 281 L1_G = DecodeSH(L0.g, L1_G); 282 L1_B = DecodeSH(L0.b, L1_B); 283 outLighting += SHEvalLinearL1(N, L1_R, L1_G, L1_B); 284 285 return outLighting; 286} 287 288float3 EvalL2(inout float3 L0, float4 L2_R, float4 L2_G, float4 L2_B, float4 L2_C, float3 N) 289{ 290 DecodeSH_L2(L0, L2_R, L2_G, L2_B, L2_C); 291 292 return SHEvalLinearL2(N, L2_R, L2_G, L2_B, L2_C); 293} 294 295float3 CalculateDiffuseLighting(v2f i) 296{ 297 APVResources apvRes = FillAPVResources(); 298 int3 texLoc = UNITY_ACCESS_INSTANCED_PROP(Props, _IndexInAtlas).xyz; 299 float3 normal = normalize(i.normal); 300 301 float3 skyShadingDirection = normal; 302 if (_ShadingMode == DEBUGPROBESHADINGMODE_PROBE_OCCLUSION) 303 { 304 float4 shadowmask = apvRes.ProbeOcclusion[texLoc]; 305 return shadowmask.rgb * 0.5 + (shadowmask.aaa * 0.5); 306 } 307 else if (_ShadingMode == DEBUGPROBESHADINGMODE_SKY_DIRECTION) 308 { 309 if (_APVSkyDirectionWeight > 0) 310 { 311 float value = 1.0f / GetCurrentExposureMultiplier(); 312 313 uint index = apvRes.SkyShadingDirectionIndices[texLoc].r * 255; 314 if (index != 255) 315 skyShadingDirection = apvRes.SkyPrecomputedDirections[index].rgb; 316 else 317 return float3(value, 0.0f, 0.0f); 318 319 if (dot(normal, skyShadingDirection) > 0.95) 320 return float3(0.0f, value, 0.0f); 321 return float3(0.0f, 0.0f, 0.0f); 322 } 323 else 324 { 325 return _DebugEmptyProbeData.xyz / GetCurrentExposureMultiplier(); 326 } 327 } 328 else 329 { 330 float3 skyOcclusion = _DebugEmptyProbeData.xyz; 331 if (_APVSkyOcclusionWeight > 0) 332 { 333 // L0 L1 334 float4 temp = float4(kSHBasis0, kSHBasis1 * normal.x, kSHBasis1 * normal.y, kSHBasis1 * normal.z); 335 skyOcclusion = dot(temp, apvRes.SkyOcclusionL0L1[texLoc].rgba); 336 } 337 338 if (_ShadingMode == DEBUGPROBESHADINGMODE_SKY_OCCLUSION_SH) 339 { 340 return skyOcclusion / GetCurrentExposureMultiplier(); 341 } 342 else 343 { 344 float4 L0_L1Rx = apvRes.L0_L1Rx[texLoc].rgba; 345 float3 L0 = L0_L1Rx.xyz; 346 347 if (_ShadingMode == DEBUGPROBESHADINGMODE_SHL0) 348 return L0; 349 350 float L1Rx = L0_L1Rx.w; 351 float4 L1G_L1Ry = apvRes.L1G_L1Ry[texLoc].rgba; 352 float4 L1B_L1Rz = apvRes.L1B_L1Rz[texLoc].rgba; 353 354 float3 bakeDiffuseLighting = EvalL1(L0, float3(L1Rx, L1G_L1Ry.w, L1B_L1Rz.w), L1G_L1Ry.xyz, L1B_L1Rz.xyz, normal); 355 bakeDiffuseLighting += L0; 356 357 if (_ShadingMode == DEBUGPROBESHADINGMODE_SHL0L1) 358 return bakeDiffuseLighting; 359 360 #ifdef PROBE_VOLUMES_L2 361 float4 L2_R = apvRes.L2_0[texLoc].rgba; 362 float4 L2_G = apvRes.L2_1[texLoc].rgba; 363 float4 L2_B = apvRes.L2_2[texLoc].rgba; 364 float4 L2_C = apvRes.L2_3[texLoc].rgba; 365 366 bakeDiffuseLighting += EvalL2(L0, L2_R, L2_G, L2_B, L2_C, normal); 367 #endif 368 if (_APVSkyOcclusionWeight > 0) 369 bakeDiffuseLighting += skyOcclusion * EvaluateAmbientProbe(skyShadingDirection); 370 371 return bakeDiffuseLighting; 372 } 373 } 374} 375 376CBUFFER_START(TouchupVolumeBounds) 377 float4 _TouchupVolumeBounds[16 * 3]; // A BBox is 3 float4 378 uint _AdjustmentVolumeCount; 379CBUFFER_END 380 381bool IsInSelection(float3 position) 382{ 383 for (uint i = 0; i < _AdjustmentVolumeCount; i++) 384 { 385 float3 center = _TouchupVolumeBounds[i * 3 + 0].xyz; 386 bool isSphere = _TouchupVolumeBounds[i * 3 + 0].w >= FLT_MAX; 387 if (isSphere) 388 { 389 float radius = _TouchupVolumeBounds[i * 3 + 1].x; 390 if (dot(position - center, position - center) < radius * radius) 391 return true; 392 } 393 else 394 { 395 float3 X = _TouchupVolumeBounds[i * 3 + 1].xyz; 396 float3 Y = _TouchupVolumeBounds[i * 3 + 2].xyz; 397 float3 Z = float3(_TouchupVolumeBounds[i * 3 + 0].w, 398 _TouchupVolumeBounds[i * 3 + 1].w, 399 _TouchupVolumeBounds[i * 3 + 2].w); 400 401 if (abs(dot(position - center, normalize(X))) < length(X) && 402 abs(dot(position - center, normalize(Y))) < length(Y) && 403 abs(dot(position - center, normalize(Z))) < length(Z)) 404 return true; 405 } 406 } 407 408 return false; 409} 410 411#endif //PROBEVOLUMEDEBUG_BASE_HLSL