@@ -55,136 +55,137 @@ bool RayMarch(float3 positionWS, float3 sampleDir, float3 normalWS, float2 posit
5555 float3 sampledPosNDC = ComputeNormalizedDeviceCoordinatesWithZ(sampledPosWS, UNITY_MATRIX_VP); // Jittered
5656 float3 sampledPosSS = float3(sampledPosNDC.xy * _ScreenSize.xy, sampledPosNDC.z);
5757
58- // If the point is behind the camera , this ray should not be cast
59- killRay = killRay || (sampledPosSS.z <= 0) ;
58+ // Due to a warning on Vulkan and Metal if returning early , this is the only way we found to avoid it.
59+ bool status = false ;
6060
61- // If this ray
62- if (killRay)
63- return false;
64-
65- // We start tracing from the center of the current pixel, and do so up to the far plane.
66- float3 rayOrigin = float3(positionSS + 0.5, deviceDepth);
67-
68- // Compute the ray direction in screen space
69- float3 rayDir = (sampledPosSS - rayOrigin);
70-
71- // Compute the reciprocal of the direction (not sure why tho ftm)
72- float3 rcpRayDir = rcp(rayDir);
73-
74- // Compute a ray step (added an abs here looks better, maybe its wrong need to check mmore)
75- int2 rayStep = int2((rcpRayDir.x) >= 0 ? 1 : 0,
76- (rcpRayDir.y) >= 0 ? 1 : 0);
77-
78- float3 raySign = float3(rcpRayDir.x >= 0 ? 1 : -1,
79- rcpRayDir.y >= 0 ? 1 : -1,
80- rcpRayDir.z >= 0 ? 1 : -1);
81- bool rayTowardsEye = rcpRayDir.z >= 0;
82-
83- // Build the bounds that start at the center of the pixel and travel to the edge of the screen
84- float tMax;
85- {
86- // Shrink the frustum by half a texel for efficiency reasons.
87- const float halfTexel = 0.5;
88-
89- float3 bounds;
90- bounds.x = clamp(sampledPosSS.x, halfTexel, _ScreenSize.x - halfTexel);
91- bounds.y = clamp(sampledPosSS.y, halfTexel, _ScreenSize.y - halfTexel);
92- // If we do not want to intersect the skybox, it is more efficient to not trace too far.
93- float maxDepth = -0.00000024; // 2^-22
94- bounds.z = (rcpRayDir.z >= 0) ? 1 : maxDepth;
95-
96- float3 dist = bounds * rcpRayDir - (rayOrigin * rcpRayDir);
97- tMax = Min3(dist.x, dist.y, dist.z);
98- }
99-
100- // Start ray marching from the next texel to avoid self-intersections.
101- float t;
61+ // If the point is behind the camera or the ray is invalid, this ray should not be cast
62+ if (!killRay || (sampledPosSS.z <= 0))
10263 {
103- // 'rayOrigin' is the exact texel center.
104- float2 dist = abs(0.5 * rcpRayDir.xy);
105- t = min(dist.x, dist.y);
64+ // We start tracing from the center of the current pixel, and do so up to the far plane.
65+ float3 rayOrigin = float3(positionSS + 0.5, deviceDepth);
66+
67+ // Compute the ray direction in screen space
68+ float3 rayDir = (sampledPosSS - rayOrigin);
69+
70+ // Compute the reciprocal of the direction (not sure why tho ftm)
71+ float3 rcpRayDir = rcp(rayDir);
72+
73+ // Compute a ray step (added an abs here looks better, maybe its wrong need to check mmore)
74+ int2 rayStep = int2((rcpRayDir.x) >= 0 ? 1 : 0,
75+ (rcpRayDir.y) >= 0 ? 1 : 0);
76+
77+ float3 raySign = float3(rcpRayDir.x >= 0 ? 1 : -1,
78+ rcpRayDir.y >= 0 ? 1 : -1,
79+ rcpRayDir.z >= 0 ? 1 : -1);
80+ bool rayTowardsEye = rcpRayDir.z >= 0;
81+
82+ // Build the bounds that start at the center of the pixel and travel to the edge of the screen
83+ float tMax;
84+ {
85+ // Shrink the frustum by half a texel for efficiency reasons.
86+ const float halfTexel = 0.5;
87+
88+ float3 bounds;
89+ bounds.x = clamp(sampledPosSS.x, halfTexel, _ScreenSize.x - halfTexel);
90+ bounds.y = clamp(sampledPosSS.y, halfTexel, _ScreenSize.y - halfTexel);
91+ // If we do not want to intersect the skybox, it is more efficient to not trace too far.
92+ float maxDepth = -0.00000024; // 2^-22
93+ bounds.z = (rcpRayDir.z >= 0) ? 1 : maxDepth;
94+
95+ float3 dist = bounds * rcpRayDir - (rayOrigin * rcpRayDir);
96+ tMax = Min3(dist.x, dist.y, dist.z);
97+ }
98+
99+ // Start ray marching from the next texel to avoid self-intersections.
100+ float t;
101+ {
102+ // 'rayOrigin' is the exact texel center.
103+ float2 dist = abs(0.5 * rcpRayDir.xy);
104+ t = min(dist.x, dist.y);
105+ }
106+
107+ int mipLevel = 0;
108+ int2 mipOffset = _DepthPyramidMipLevelOffsets[mipLevel];
109+ int iterCount = 0;
110+ bool hit = false;
111+ bool miss = false;
112+ bool belowMip0 = false; // This value is set prior to entering the cell
113+
114+ while (!(hit || miss) && (t <= tMax) && (iterCount < _IndirectDiffuseSteps))
115+ {
116+ rayPos = rayOrigin + t * rayDir;
117+
118+ // Ray position often ends up on the edge. To determine (and look up) the right cell,
119+ // we need to bias the position by a small epsilon in the direction of the ray.
120+ float2 sgnEdgeDist = round(rayPos.xy) - rayPos.xy;
121+ float2 satEdgeDist = clamp(raySign.xy * sgnEdgeDist + GI_TRACE_EPS, 0, GI_TRACE_EPS);
122+ rayPos.xy += raySign.xy * satEdgeDist;
123+
124+ int2 mipCoord = (int2)rayPos.xy >> mipLevel;
125+ // Bounds define 4 faces of a cube:
126+ // 2 walls in front of the ray, and a floor and a base below it.
127+ float4 bounds;
128+
129+ bounds.z = LOAD_TEXTURE2D_X(_CameraDepthTexture, mipOffset + mipCoord).r;
130+ bounds.xy = (mipCoord + rayStep) << mipLevel;
131+
132+ // We define the depth of the base as the depth value as:
133+ // b = DeviceDepth((1 + thickness) * LinearDepth(d))
134+ // b = ((f - n) * d + n * (1 - (1 + thickness))) / ((f - n) * (1 + thickness))
135+ // b = ((f - n) * d - n * thickness) / ((f - n) * (1 + thickness))
136+ // b = d / (1 + thickness) - n / (f - n) * (thickness / (1 + thickness))
137+ // b = d * k_s + k_b
138+ bounds.w = bounds.z * _IndirectDiffuseThicknessScale + _IndirectDiffuseThicknessBias;
139+
140+ float4 dist = bounds * rcpRayDir.xyzz - (rayOrigin.xyzz * rcpRayDir.xyzz);
141+ float distWall = min(dist.x, dist.y);
142+ float distFloor = dist.z;
143+ float distBase = dist.w;
144+
145+ // Note: 'rayPos' given by 't' can correspond to one of several depth values:
146+ // - above or exactly on the floor
147+ // - inside the floor (between the floor and the base)
148+ // - below the base
149+ bool belowFloor = rayPos.z < bounds.z;
150+ bool aboveBase = rayPos.z >= bounds.w;
151+
152+ bool insideFloor = belowFloor && aboveBase;
153+ bool hitFloor = (t <= distFloor) && (distFloor <= distWall);
154+
155+ // Game rules:
156+ // * if the closest intersection is with the wall of the cell, switch to the coarser MIP, and advance the ray.
157+ // * if the closest intersection is with the heightmap below, switch to the finer MIP, and advance the ray.
158+ // * if the closest intersection is with the heightmap above, switch to the finer MIP, and do NOT advance the ray.
159+ // Victory conditions:
160+ // * See below. Do NOT reorder the statements!
161+
162+ miss = belowMip0 && insideFloor;
163+ hit = (mipLevel == 0) && (hitFloor || insideFloor);
164+ belowMip0 = (mipLevel == 0) && belowFloor;
165+
166+ // 'distFloor' can be smaller than the current distance 't'.
167+ // We can also safely ignore 'distBase'.
168+ // If we hit the floor, it's always safe to jump there.
169+ // If we are at (mipLevel != 0) and we are below the floor, we should not move.
170+ t = hitFloor ? distFloor : (((mipLevel != 0) && belowFloor) ? t : distWall);
171+ rayPos.z = bounds.z; // Retain the depth of the potential intersection
172+
173+ // Warning: both rays towards the eye, and tracing behind objects has linear
174+ // rather than logarithmic complexity! This is due to the fact that we only store
175+ // the maximum value of depth, and not the min-max.
176+ mipLevel += (hitFloor || belowFloor || rayTowardsEye) ? -1 : 1;
177+ mipLevel = clamp(mipLevel, 0, 6);
178+ mipOffset = _DepthPyramidMipLevelOffsets[mipLevel];
179+ // mipLevel = 0;
180+
181+ iterCount++;
182+ }
183+
184+ // Treat intersections with the sky as misses.
185+ miss = miss || ((rayPos.z == 0));
186+ status = hit && !miss;
106187 }
107-
108- int mipLevel = 0;
109- int2 mipOffset = _DepthPyramidMipLevelOffsets[mipLevel];
110- int iterCount = 0;
111- bool hit = false;
112- bool miss = false;
113- bool belowMip0 = false; // This value is set prior to entering the cell
114-
115- while (!(hit || miss) && (t <= tMax) && (iterCount < _IndirectDiffuseSteps))
116- {
117- rayPos = rayOrigin + t * rayDir;
118-
119- // Ray position often ends up on the edge. To determine (and look up) the right cell,
120- // we need to bias the position by a small epsilon in the direction of the ray.
121- float2 sgnEdgeDist = round(rayPos.xy) - rayPos.xy;
122- float2 satEdgeDist = clamp(raySign.xy * sgnEdgeDist + GI_TRACE_EPS, 0, GI_TRACE_EPS);
123- rayPos.xy += raySign.xy * satEdgeDist;
124-
125- int2 mipCoord = (int2)rayPos.xy >> mipLevel;
126- // Bounds define 4 faces of a cube:
127- // 2 walls in front of the ray, and a floor and a base below it.
128- float4 bounds;
129-
130- bounds.z = LOAD_TEXTURE2D_X(_CameraDepthTexture, mipOffset + mipCoord).r;
131- bounds.xy = (mipCoord + rayStep) << mipLevel;
132-
133- // We define the depth of the base as the depth value as:
134- // b = DeviceDepth((1 + thickness) * LinearDepth(d))
135- // b = ((f - n) * d + n * (1 - (1 + thickness))) / ((f - n) * (1 + thickness))
136- // b = ((f - n) * d - n * thickness) / ((f - n) * (1 + thickness))
137- // b = d / (1 + thickness) - n / (f - n) * (thickness / (1 + thickness))
138- // b = d * k_s + k_b
139- bounds.w = bounds.z * _IndirectDiffuseThicknessScale + _IndirectDiffuseThicknessBias;
140-
141- float4 dist = bounds * rcpRayDir.xyzz - (rayOrigin.xyzz * rcpRayDir.xyzz);
142- float distWall = min(dist.x, dist.y);
143- float distFloor = dist.z;
144- float distBase = dist.w;
145-
146- // Note: 'rayPos' given by 't' can correspond to one of several depth values:
147- // - above or exactly on the floor
148- // - inside the floor (between the floor and the base)
149- // - below the base
150- bool belowFloor = rayPos.z < bounds.z;
151- bool aboveBase = rayPos.z >= bounds.w;
152-
153- bool insideFloor = belowFloor && aboveBase;
154- bool hitFloor = (t <= distFloor) && (distFloor <= distWall);
155-
156- // Game rules:
157- // * if the closest intersection is with the wall of the cell, switch to the coarser MIP, and advance the ray.
158- // * if the closest intersection is with the heightmap below, switch to the finer MIP, and advance the ray.
159- // * if the closest intersection is with the heightmap above, switch to the finer MIP, and do NOT advance the ray.
160- // Victory conditions:
161- // * See below. Do NOT reorder the statements!
162-
163- miss = belowMip0 && insideFloor;
164- hit = (mipLevel == 0) && (hitFloor || insideFloor);
165- belowMip0 = (mipLevel == 0) && belowFloor;
166-
167- // 'distFloor' can be smaller than the current distance 't'.
168- // We can also safely ignore 'distBase'.
169- // If we hit the floor, it's always safe to jump there.
170- // If we are at (mipLevel != 0) and we are below the floor, we should not move.
171- t = hitFloor ? distFloor : (((mipLevel != 0) && belowFloor) ? t : distWall);
172- rayPos.z = bounds.z; // Retain the depth of the potential intersection
173-
174- // Warning: both rays towards the eye, and tracing behind objects has linear
175- // rather than logarithmic complexity! This is due to the fact that we only store
176- // the maximum value of depth, and not the min-max.
177- mipLevel += (hitFloor || belowFloor || rayTowardsEye) ? -1 : 1;
178- mipLevel = clamp(mipLevel, 0, 6);
179- mipOffset = _DepthPyramidMipLevelOffsets[mipLevel];
180- // mipLevel = 0;
181-
182- iterCount++;
183- }
184-
185- // Treat intersections with the sky as misses.
186- miss = miss || ((rayPos.z == 0));
187- return hit && !miss;
188+ return status;
188189}
189190
190191[numthreads(INDIRECT_DIFFUSE_TILE_SIZE, INDIRECT_DIFFUSE_TILE_SIZE, 1)]
0 commit comments