Skip to content

Commit

Permalink
SSR support
Browse files Browse the repository at this point in the history
  • Loading branch information
tippesi committed Oct 17, 2024
1 parent 17d418b commit 2d67be5
Show file tree
Hide file tree
Showing 11 changed files with 1,481 additions and 989 deletions.
9 changes: 9 additions & 0 deletions data/shader/common/ign.hsh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ float GetInterleavedGradientNoise(vec2 screenPos) {
float x = float(screenPos.x) + 5.588238 * float(frame);
float y = float(screenPos.y) + 5.588238 * float(frame);

vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
return fract(magic.z * fract(dot(vec2(x, y), magic.xy)));
}

float GetInterleavedGradientNoise(vec2 screenPos, uint frameCount) {
uint frame = globalData.frameCount % frameCount;
float x = float(screenPos.x) + 5.588238 * float(frame);
float y = float(screenPos.y) + 5.588238 * float(frame);

vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
return fract(magic.z * fract(dot(vec2(x, y), magic.xy)));
}
263 changes: 263 additions & 0 deletions data/shader/common/traceScreenSpace.hsh
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;

}
2 changes: 2 additions & 0 deletions data/shader/globals.hsh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ layout(set = 1, binding = 31, std140) uniform GlobalBuffer {
float deltaTime;
uint frameCount;
float mipLodBias;
float cameraNearPlane;
float cameraFarPlane;
} globalData;

layout(set = 0, binding = 3) uniform texture2D bindlessTextures[TEXTURE_COUNT];
Expand Down
12 changes: 6 additions & 6 deletions data/shader/reflection/rtreflection.csh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

layout (local_size_x = 8, local_size_y = 4) in;

layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D rtrImage;
layout (set = 3, binding = 0, rgba16f) uniform image2D rtrImage;

layout(set = 3, binding = 1) uniform sampler2D normalTexture;
layout(set = 3, binding = 2) uniform sampler2D depthTexture;
Expand Down Expand Up @@ -95,9 +95,9 @@ void main() {
float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r;
material.roughness *= material.roughnessMap ? roughness : 1.0;

vec3 reflection = vec3(0.0);
vec4 reflection = imageLoad(rtrImage, pixel);

if (material.roughness <= 1.0 && depth < 1.0) {
if (material.roughness <= 1.0 && depth < 1.0 && reflection.a == 0.0) {

const int sampleCount = uniforms.sampleCount;

Expand Down Expand Up @@ -160,15 +160,15 @@ void main() {

float radianceMax = max(max(max(radiance.r,
max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01);
reflection += radiance * (uniforms.radianceLimit / radianceMax);
reflection.rgb += radiance * (uniforms.radianceLimit / radianceMax);
}
}

reflection /= float(sampleCount);
reflection.rgb /= float(sampleCount);

}

imageStore(rtrImage, pixel, vec4(reflection, 1.0));
imageStore(rtrImage, pixel, reflection);
}

}
Expand Down
Loading

0 comments on commit 2d67be5

Please sign in to comment.