First step for HBAO. Not working of course

This commit is contained in:
Olivier Prat 2018-04-19 17:34:28 +02:00
parent 5dcb7f622a
commit 5e9355235c
3 changed files with 151 additions and 74 deletions

View file

@ -11,11 +11,13 @@
<@if not SSAO_SLH@>
<@def SSAO_SLH@>
#define SSAO_USE_HORIZON_BASED 1
<@func declarePackOcclusionDepth()@>
const float FAR_PLANE_Z = -300.0;
float CSZToDephtKey(float z) {
float CSZToDepthKey(float z) {
return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0);
}
vec3 packOcclusionDepth(float occlusion, float depth) {
@ -156,24 +158,25 @@ float evalDiskRadius(float Zeye, vec2 imageSize) {
return ssDiskRadius;
}
const float TWO_PI = 6.28;
const float PI = 3.1415926;
const float TWO_PI = 6.2831852;
vec3 getUnitTapLocation(int sampleNumber, float spinAngle){
vec3 getUnitTapLocation(int sampleNumber, float spiralTurns, float spinAngle, float angleRange){
// Radius relative to ssR
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
float angle = alpha * (spiralTurns * angleRange) + spinAngle;
return vec3(cos(angle), sin(angle), alpha);
}
vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) {
vec3 tap = getUnitTapLocation(sampleNumber, spinAngle);
vec3 getTapLocationSSAO(int sampleNumber, float spinAngle, float outerRadius) {
vec3 tap = getUnitTapLocation(sampleNumber, getNumSpiralTurns(), spinAngle, TWO_PI);
tap.xy *= tap.z;
tap *= outerRadius;
return tap;
}
vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) {
vec3 tap = getTapLocation(sampleNumber, spinAngle, outerRadius);
vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) {
vec3 tap = getTapLocationSSAO(sampleNumber, spinAngle, outerRadius);
vec2 tapPos = pixelPos + tap.xy;
if (!(isBorderingEnabled() > 0.0)) {
@ -196,24 +199,7 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius,
tapPos.y -= (imageSize.y - tapPos.y);
redoTap = true;
}
/*
if ((tapPos.x < 0.5)) {
tapPos.x = 0.5;
redoTap = true;
} else if ((tapPos.x > imageSize.x - 0.5)) {
tapPos.x = imageSize.x - 0.5;
redoTap = true;
}
if ((tapPos.y < 0.5)) {
tapPos.y = 0.5;
redoTap = true;
} else if ((tapPos.y > imageSize.y - 0.5)) {
tapPos.y = imageSize.y - 0.5;
redoTap = true;
}
*/
if (redoTap) {
tap.xy = tapPos - pixelPos;
tap.z = length(tap.xy);
@ -228,14 +214,17 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius,
<@func declareFetchDepthPyramidMap()@>
// the depth pyramid texture
uniform sampler2D pyramidMap;
float getZEye(ivec2 pixel, int level) {
float getZEyeAtPixel(ivec2 pixel, int level) {
return -texelFetch(pyramidMap, pixel, level).x;
}
float getZEyeAtUV(vec2 texCoord, int level) {
return -texture(pyramidMap, texCoord, level).x;
}
const int LOG_MAX_OFFSET = 3;
const int MAX_MIP_LEVEL = 5;
int evalMipFromRadius(float radius) {
@ -243,7 +232,6 @@ int evalMipFromRadius(float radius) {
return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
}
vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
ivec2 ssP = ivec2(tap.xy) + ssC;
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
@ -292,10 +280,18 @@ vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
<@func declareEvalObscurance()@>
float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) {
vec3 v = Q - C;
vec3 fastAcos(vec3 x) {
// [Eberly2014] GPGPU Programming for Games and Science
vec3 absX = abs(x);
vec3 res = absX * (-0.156583) + vec3(PI / 2.0);
res *= sqrt(vec3(1.0) - absX);
return mix(res, vec3(PI) - res, greaterThanEqual(x, vec3(0)));
}
float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 tapPosition) {
vec3 v = tapPosition - centerPosition;
float vv = dot(v, v);
float vn = dot(v, n_C);
float vn = dot(v, centerNormal);
// Fall off function as recommended in SAO paper
const float epsilon = 0.01;
@ -303,6 +299,95 @@ float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) {
return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0);
}
vec2 searchHorizons(int side, float centerDepth, vec2 centerPixelUV, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragNormalES) {
vec2 searchVec = deltaTap * ssDiskRadius;
vec2 absSearchVec = abs(searchVec);
vec2 horizons = vec2(-PI/2.0, -PI/2.0);
vec3 centerPoint = vec3(centerPixelUV, centerDepth);
int stepIndex;
vec2 tapPixelUV;
if (absSearchVec.x > absSearchVec.y) {
int stepCount = int(ceil(absSearchVec.x));
// Positive search for h2
tapPixelUV = centerPixelUV;
deltaTap = (searchVec / searchVec.x) / imageSize;
stepIndex = stepCount;
while (stepIndex>0 && tapPixelUV.x < 1.0) {
tapPixelUV += deltaTap;
// Don't clamp for the moment
float tapDepth = getZEyeAtUV(tapPixelUV, 0);
vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint;
horizons.y = max(horizons.y, normalize(deltaVec).z);
--stepIndex;
}
// Negative search for h1
tapPixelUV = centerPixelUV;
stepIndex = stepCount;
while (stepIndex>0 && tapPixelUV.x > 0.0) {
tapPixelUV -= deltaTap;
// Don't clamp for the moment
float tapDepth = getZEyeAtUV(tapPixelUV, 0);
vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint;
horizons.x = max(horizons.x, normalize(deltaVec).z);
--stepIndex;
}
} else {
int stepCount = int(ceil(absSearchVec.y));
// Positive search for h2
tapPixelUV = centerPixelUV;
deltaTap = (searchVec / searchVec.y) / imageSize;
stepIndex = stepCount;
while (stepIndex>0 && tapPixelUV.y < 1.0) {
tapPixelUV += deltaTap;
// Don't clamp for the moment
float tapDepth = getZEyeAtUV(tapPixelUV, 0);
vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint;
horizons.y = max(horizons.y, normalize(deltaVec).z);
--stepIndex;
}
// Negative search for h1
tapPixelUV = centerPixelUV;
stepIndex = stepCount;
while (stepIndex>0 && tapPixelUV.y > 0.0) {
tapPixelUV -= deltaTap;
// Don't clamp for the moment
float tapDepth = getZEyeAtUV(tapPixelUV, 0);
vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint;
horizons.x = max(horizons.x, normalize(deltaVec).z);
--stepIndex;
}
}
vec3 angles = acos(vec3(horizons, fragNormalES.z))-PI/2.0;
angles.x = -angles.x;
// Clamp to limit horizon defined by normal plane
horizons.xy = angles.zz + max(angles.xy - angles.zz, vec2(-PI/2.0, PI/2.0));
return horizons;
}
float integrateArc(float h1, float h2) {
vec2 cosh = cos(vec2(h1, h2));
return 2.0 - cosh.x - cosh.y;
}
float evalVisibilityHBAO(int side, float centerDepth, vec2 centerPixelUV, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragNormalES) {
vec2 horizonAngles = searchHorizons(side, centerDepth, centerPixelUV, imageSize, deltaTap, ssDiskRadius, fragNormalES);
return integrateArc(horizonAngles.x, horizonAngles.y);
}
<@endfunc@>
<@func declareBlurPass(axis)@>

View file

@ -50,7 +50,7 @@ void main(void) {
ivec2 ssC = ivec2(cursorPixelPos);
// Fetch the z under the pixel (stereo or not)
float Zeye = getZEye(ssC, 0);
float Zeye = getZEyeAtPixel(ssC, 0);
// Stereo side info
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
@ -84,7 +84,7 @@ void main(void) {
bool keep = false;
for (int i = 0; i < getNumSamples(); ++i) {
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize);
vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize);
// The occluding point in camera space
vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy;
@ -97,7 +97,7 @@ void main(void) {
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q);
sum += float(tap.z > 0.0) * evalVisibilitySSAO(Cp, Cn, Q);
}
@ -114,7 +114,7 @@ void main(void) {
}
!>
outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);
outFragColor = vec4(packOcclusionDepth(A, CSZToDepthKey(Cp.z)), 1.0);
if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) {
// outFragColor = vec4(vec3(A), 1.0);

View file

@ -24,63 +24,55 @@ void main(void) {
// Pixel being shaded
vec2 fragCoord = gl_FragCoord.xy;
ivec2 ssC = ivec2(fragCoord.xy);
ivec2 centerPixelPos = ivec2(fragCoord.xy);
// Fetch the z under the pixel (stereo or not)
float Zeye = getZEye(ssC, 0);
float Zeye = getZEyeAtPixel(centerPixelPos, 0);
// Stereo side info
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
ivec4 side = getStereoSideInfo(centerPixelPos.x, getResolutionLevel());
// From now on, ssC is the pixel pos in the side
ssC.x -= side.y;
vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize;
// From now on, centerPixelPos is the pixel pos in the side
centerPixelPos.x -= side.y;
vec2 fragUVPos = (vec2(centerPixelPos) + vec2(0.5)) / imageSize;
// The position and normal of the pixel fragment in Eye space
vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos);
vec3 Cn = evalEyeNormal(Cp);
vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos);
vec3 fragNormalES = evalEyeNormal(fragPositionES);
// Choose the screen-space sample radius
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
float ssDiskRadius = evalDiskRadius(fragPositionES.z, imageSize);
#if SSAO_USE_HORIZON_BASED
ssDiskRadius = min(ssDiskRadius, 3.0);
#endif
// Let's make noise
float randomPatternRotationAngle = getAngleDithering(ssC);
//vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz;
//float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp);
float randomPatternRotationAngle = getAngleDithering(centerPixelPos);
// Accumulate the Obscurance for each samples
float sum = 0.0;
// Accumulate the visibility for each samples
float visibilitySum = 0.0;
for (int i = 0; i < getNumSamples(); ++i) {
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize);
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q);
#if SSAO_USE_HORIZON_BASED
vec3 deltaTap = getUnitTapLocation(i, 1, randomPatternRotationAngle, PI);
visibilitySum += evalVisibilityHBAO(side.x, Zeye, fragUVPos, imageSize, deltaTap.xy, ssDiskRadius, fragNormalES);
#else
vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, centerPixelPos, imageSize);
vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize);
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
visibilitySum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES);
#endif
}
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
float occlusion = max(0.0, 1.0 - visibilitySum * getObscuranceScaling() * 5.0 * getInvNumSamples());
// KEEP IT for Debugging
// Bilateral box-filter over a quad for free, respecting depth edges
// (the difference that this makes is subtle)
if (abs(dFdx(Cp.z)) < 0.02) {
A -= dFdx(A) * ((ssC.x & 1) - 0.5);
/* if (abs(dFdx(fragPositionES.z)) < 0.02) {
occlusion -= dFdx(occlusion) * ((centerPixelPos.x & 1) - 0.5);
}
if (abs(dFdy(Cp.z)) < 0.02) {
A -= dFdy(A) * ((ssC.y & 1) - 0.5);
}
outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);
/* {
vec3 tap = getTapLocationClamped(2, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize);
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
vec2 fetchUV = vec2(tapUVZ.x + side.w * 0.5 * (side.x - tapUVZ.x), tapUVZ.y);
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
outFragColor = vec4(fetchUV, 0.0, 1.0);
if (abs(dFdy(fragPositionES.z)) < 0.02) {
occlusion -= dFdy(occlusion) * ((centerPixelPos.y & 1) - 0.5);
}*/
outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0);
}