-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
1,481 additions
and
989 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
// By Morgan McGuire and Michael Mara at Williams College 2014 | ||
// Released as open source under the BSD 2-Clause License | ||
// http://opensource.org/licenses/BSD-2-Clause | ||
|
||
// Some ideas: https://willpgfx.com/2015/07/screen-space-glossy-reflections/ | ||
// More: https://interplayoflight.wordpress.com/2019/09/07/hybrid-screen-space-reflections/ | ||
|
||
#include <convert.hsh> | ||
#include <../globals.hsh> | ||
|
||
#define point2 vec2 | ||
#define point3 vec3 | ||
|
||
float distanceSquared(vec2 a, vec2 b) { a -= b; return dot(a, a); } | ||
|
||
bool intersectsDepthBuffer(float z, float minZ, float maxZ, float thickness, float strideCutoff) { | ||
/* | ||
* Based on how far away from the camera the depth is, | ||
* adding a bit of extra thickness can help improve some | ||
* artifacts. Driving this value up too high can cause | ||
* artifacts of its own. | ||
*/ | ||
float depthScale = min(1.0f, z * strideCutoff); | ||
//thickness *= mix(0.0f, 2.0f, depthScale); | ||
return (maxZ >= z - thickness) && (minZ < z); | ||
} | ||
|
||
// Returns true if the ray hit something | ||
bool traceScreenSpace( | ||
// Camera-space ray origin, which must be within the view volume | ||
point3 csOrig, | ||
|
||
// Unit length camera-space ray direction | ||
vec3 csDir, | ||
|
||
// The camera-space Z buffer (all negative values) | ||
sampler2D csZBuffer, | ||
|
||
// Camera space thickness to ascribe to each pixel in the depth buffer | ||
float zThickness, | ||
|
||
// Step in horizontal or vertical pixels between samples. This is a float | ||
// because integer math is slow on GPUs, but should be set to an integer >= 1 | ||
float stride, | ||
|
||
// Number between 0 and 1 for how far to bump the ray in stride units | ||
// to conceal banding artifacts | ||
float jitter, | ||
|
||
// Maximum number of iterations. Higher gives better images but may be slow | ||
const float maxSteps, | ||
|
||
// Maximum camera-space distance to trace before returning a miss | ||
float maxDistance, | ||
|
||
// Pixel coordinates of the first intersection with the scene | ||
out point2 hitPixel, | ||
|
||
// Camera space location of the ray hit | ||
out point3 hitPoint, | ||
|
||
out point3 minPoint, | ||
|
||
out point3 maxPoint) { | ||
|
||
// Clip to the near plane | ||
float rayLength = ((csOrig.z + csDir.z * maxDistance) > -globalData.cameraNearPlane) ? | ||
(-globalData.cameraNearPlane - csOrig.z) / csDir.z : maxDistance; | ||
point3 csEndPoint = csOrig + csDir * rayLength; | ||
|
||
vec2 csZBufferSize = vec2(textureSize(csZBuffer, 0)); | ||
|
||
// Project into homogeneous clip space | ||
vec4 H0 = globalData.pMatrix * vec4(csOrig, 1.0); | ||
vec4 H1 = globalData.pMatrix * vec4(csEndPoint, 1.0); | ||
float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w; | ||
|
||
// The interpolated homogeneous version of the camera-space points | ||
point3 Q0 = csOrig * k0; | ||
point3 Q1 = csEndPoint * k1; | ||
|
||
// Screen-space endpoints | ||
point2 P0 = (H0.xy * k0) * 0.5 + 0.5; | ||
point2 P1 = 0.5 * (H1.xy * k1) + 0.5; | ||
P0 *= csZBufferSize; | ||
P1 *= csZBufferSize; | ||
|
||
// If the line is degenerate, make it cover at least one pixel | ||
// to avoid handling zero-pixel extent as a special case later | ||
P1 += vec2((distanceSquared(P0, P1) < 0.0001) ? 0.01 : 0.0); | ||
vec2 delta = P1 - P0; | ||
|
||
// Permute so that the primary iteration is in x to collapse | ||
// all quadrant-specific DDA cases later | ||
bool permute = false; | ||
if (abs(delta.x) < abs(delta.y)) { | ||
// This is a more-vertical line | ||
permute = true; delta = delta.yx; P0 = P0.yx; P1 = P1.yx; | ||
} | ||
|
||
float stepDir = sign(delta.x); | ||
float invdx = stepDir / delta.x; | ||
|
||
// Track the derivatives of Q and k | ||
vec3 dQ = (Q1 - Q0) * invdx; | ||
float dk = (k1 - k0) * invdx; | ||
vec2 dP = vec2(stepDir, delta.y * invdx); | ||
|
||
// Scale derivatives by the desired pixel stride and then | ||
// offset the starting values by the jitter fraction | ||
|
||
float strideScale = 1.0 - min(1.0, abs(csOrig.z) * 0.01); | ||
stride = 1.0 + strideScale * stride; | ||
|
||
P0 += dP; | ||
Q0 += dQ; | ||
k0 += dk; | ||
|
||
dP *= stride; | ||
dQ *= stride; | ||
dk *= stride; | ||
|
||
P0 += dP * jitter; | ||
Q0 += dQ * jitter; | ||
k0 += dk * jitter; | ||
|
||
// Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, k from k0 to k1 | ||
point3 Q = Q0; | ||
|
||
// Adjust end condition for iteration direction | ||
float end = P1.x * stepDir; | ||
|
||
float k = k0, stepCount = 0.0, prevZMaxEstimate = csOrig.z; | ||
float rayZMin = prevZMaxEstimate, rayZMax = prevZMaxEstimate; | ||
float sceneZMax = rayZMax + 100; | ||
point2 P = P0; | ||
for (; | ||
((P.x * stepDir) <= end) && (stepCount < maxSteps) && | ||
!intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01) && | ||
(sceneZMax != 0); | ||
P += dP, Q.z += dQ.z, k += dk, ++stepCount) { | ||
|
||
rayZMin = prevZMaxEstimate; | ||
rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); | ||
prevZMaxEstimate = rayZMax; | ||
if (rayZMin > rayZMax) { | ||
float t = rayZMin; rayZMin = rayZMax; rayZMax = t; | ||
} | ||
|
||
hitPixel = permute ? P.yx : P; | ||
// You may need hitPixel.y = csZBufferSize.y - hitPixel.y; here if your vertical axis | ||
// is different than ours in screen space | ||
sceneZMax = ConvertDepthToViewSpaceDepth(texelFetch(csZBuffer, ivec2(hitPixel), 0).r); | ||
} | ||
|
||
minPoint = Q0 + dQ * (stepCount - 2.0); | ||
maxPoint = Q0 + dQ * (stepCount - 1.0); | ||
|
||
minPoint /= (k - 2.0 * dk); | ||
maxPoint /= (k - 1.0 * dk); | ||
|
||
// Advance Q based on the number of steps | ||
Q.xy += dQ.xy * stepCount; | ||
hitPoint = Q * (1.0 / k); | ||
|
||
return intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01); | ||
} | ||
|
||
bool traceScreenSpace( | ||
// Camera-space ray origin, which must be within the view volume | ||
point3 csOrig, | ||
|
||
// Unit length camera-space ray direction | ||
vec3 csDir, | ||
|
||
// The camera-space Z buffer (all negative values) | ||
sampler2D csZBuffer, | ||
|
||
// Camera space thickness to ascribe to each pixel in the depth buffer | ||
float zThickness, | ||
|
||
// Step in horizontal or vertical pixels between samples. This is a float | ||
// because integer math is slow on GPUs, but should be set to an integer >= 1 | ||
float stride, | ||
|
||
// Number between 0 and 1 for how far to bump the ray in stride units | ||
// to conceal banding artifacts | ||
float jitter, | ||
|
||
// Maximum number of iterations. Higher gives better images but may be slow | ||
const float maxSteps, | ||
|
||
// Maximum camera-space distance to trace before returning a miss | ||
float maxDistance, | ||
|
||
// Pixel coordinates of the first intersection with the scene | ||
out point2 hitPixel, | ||
|
||
// Camera space location of the ray hit | ||
out point3 hitPoint) { | ||
|
||
point3 minPoint, maxPoint; | ||
return traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, hitPixel, hitPoint, minPoint, maxPoint); | ||
|
||
} | ||
|
||
bool traceScreenSpaceAdvanced( | ||
// Camera-space ray origin, which must be within the view volume | ||
point3 csOrig, | ||
|
||
// Unit length camera-space ray direction | ||
vec3 csDir, | ||
|
||
// The camera-space Z buffer (all negative values) | ||
sampler2D csZBuffer, | ||
|
||
// Camera space thickness to ascribe to each pixel in the depth buffer | ||
float zThickness, | ||
|
||
// Step in horizontal or vertical pixels between samples. This is a float | ||
// because integer math is slow on GPUs, but should be set to an integer >= 1 | ||
float stride, | ||
|
||
// Number between 0 and 1 for how far to bump the ray in stride units | ||
// to conceal banding artifacts | ||
float jitter, | ||
|
||
// Maximum number of iterations. Higher gives better images but may be slow | ||
float maxSteps, | ||
|
||
// Maximum camera-space distance to trace before returning a miss | ||
float maxDistance, | ||
|
||
// Pixel coordinates of the first intersection with the scene | ||
out point2 hitPixel, | ||
|
||
// Camera space location of the ray hit | ||
out point3 hitPoint) { | ||
|
||
point3 minPoint, maxPoint; | ||
if(traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, hitPixel, hitPoint, minPoint, maxPoint)) { | ||
|
||
} | ||
|
||
maxSteps /= 2.0; | ||
|
||
csOrig = minPoint; | ||
csDir = normalize(maxPoint - minPoint); | ||
stride = max(1.0, stride / maxSteps);; | ||
zThickness /= maxSteps; | ||
maxDistance = 20.0 * distance(maxPoint, minPoint); | ||
|
||
vec2 newHitPixel; | ||
vec3 newHitPoint; | ||
if (traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, newHitPixel, newHitPoint, minPoint, maxPoint)) { | ||
hitPixel = newHitPixel; | ||
hitPoint = newHitPoint; | ||
return true; | ||
} | ||
|
||
return false; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.