mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 23:33:48 +02:00
First step for HBAO. Not working of course
This commit is contained in:
parent
5dcb7f622a
commit
5e9355235c
3 changed files with 151 additions and 74 deletions
|
@ -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)@>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue