fixing ao

This commit is contained in:
samcake 2016-08-03 15:45:22 -07:00
parent a5c91c0602
commit b4e5b60656
8 changed files with 159 additions and 129 deletions

View file

@ -487,7 +487,7 @@ const gpu::PipelinePointer& DebugAmbientOcclusion::getDebugPipeline() {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setColorWriteMask(true, true, true, false);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
// Good to go add the brand new pipeline
_debugPipeline = gpu::Pipeline::create(program, state);
}

View file

@ -100,7 +100,7 @@ public:
float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions
int numSamples{ 11 };
int resolutionLevel{ 0 };
int blurRadius{ 0 }; // 0 means no blurring
int blurRadius{ 3 }; // 0 means no blurring
bool ditheringEnabled{ true }; // randomize the distribution of rays per pixel, should always be true
bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true
double gpuTime{ 0.0 };

View file

@ -85,6 +85,10 @@ float getStereoSideHeight(int resolutionLevel) {
return float(int(frameTransform._pixelInfo.w) >> resolutionLevel);
}
vec2 getSideImageSize(int resolutionLevel) {
return vec2(float(int(frameTransform._stereoInfo.y) >> resolutionLevel), float(int(frameTransform._pixelInfo.w) >> resolutionLevel));
}
ivec4 getStereoSideInfo(int xPos, int resolutionLevel) {
int sideWidth = int(getStereoSideWidth(resolutionLevel));
return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo());

View file

@ -178,14 +178,16 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
// Debugging stages
{
// Debugging Deferred buffer job
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
addJob<DebugSubsurfaceScattering>("DebugScattering", deferredLightingInputs);
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);
// Debugging Deferred buffer job
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
// Scene Octree Debuging job
{

View file

@ -126,6 +126,115 @@ float getBlurCoef(int c) {
<@endfunc@>
<@func declareSamplingDisk()@>
float evalDiskRadius(float Zeye, vec2 imageSize) {
// Choose the screen-space sample radius
// proportional to the projected area of the sphere
float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale();
// clamp the disk to fit in the image otherwise too many unknown
ssDiskRadius = min(ssDiskRadius, imageSize.y * 0.5);
return ssDiskRadius;
}
const float TWO_PI = 6.28;
vec3 getUnitTapLocation(int sampleNumber, float spinAngle){
// Radius relative to ssR
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
return vec3(cos(angle), sin(angle), alpha);
}
vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) {
vec3 tap = getUnitTapLocation(sampleNumber, spinAngle);
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);
vec2 tapPos = pixelPos + tap.xy;
if (!(isBorderingEnabled() > 0.0)) {
return tap;
}
bool redoTap = false;
if ((tapPos.x < 0.5)) {
tapPos.x = -tapPos.x;
redoTap = true;
} else if ((tapPos.x > imageSize.x - 0.5)) {
tapPos.x -= (imageSize.x - tapPos.x);
redoTap = true;
}
if ((tapPos.y < 0.5)) {
tapPos.y = -tapPos.y;
redoTap = true;
} else if ((tapPos.y > imageSize.y - 0.5)) {
tapPos.y -= (imageSize.y - tapPos.y);
redoTap = true;
}
if (redoTap) {
tap.xy = tapPos - pixelPos;
tap.z = length(tap.xy);
}
/*
if ((tapPos.x < 0.0) || (tapPos.x >= imageSize.x)) {
// tapPos.x = pixelPos.x - tapVec.x;
tap.x = -tap.x;
}
if ((tapPos.y < 0.0) || (tapPos.y >= imageSize.y)) {
// tapPos.y = pixelPos.y - tapVec.y;
tap.y = -tap.y;
}*/
return tap;
}
<@endfunc@>
<@func declareFetchDepthPyramidMap()@>
const int LOG_MAX_OFFSET = 3;
const int MAX_MIP_LEVEL = 5;
// the depth pyramid texture
uniform sampler2D pyramidMap;
float getZEye(ivec2 pixel) {
return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x;
}
vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
// Derivation:
// mipLevel = floor(log(ssR / MAX_OFFSET));
int mipLevel = clamp(findMSB(int(tap.z)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
ivec2 ssP = ivec2(tap.xy) + ssC;
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
vec3 P;
// We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
// Manually clamp to the texture size because texelFetch bypasses the texture unit
ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1));
P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r;
// Offset to pixel center
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize;
P = evalEyePositionFromZeye(side.x, P.z, tapUV);
return P;
}
<@endfunc@>
<@func declareBlurPass(axis)@>
<$declarePackOcclusionDepth()$>

View file

@ -11,6 +11,9 @@
<@include ssao.slh@>
<$declareAmbientOcclusion()$>
<$declareFetchDepthPyramidMap()$>
<$declareSamplingDisk()$>
<$declarePackOcclusionDepth()$>
struct DebugParams{
@ -24,15 +27,6 @@ uniform debugAmbientOcclusionBuffer {
vec2 getDebugCursorTexcoord(){
return debugParams.pixelInfo.xy;
}
const int LOG_MAX_OFFSET = 3;
const int MAX_MIP_LEVEL = 5;
// the depth pyramid texture
uniform sampler2D pyramidMap;
float getZEye(ivec2 pixel) {
return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x;
}
out vec4 outFragColor;
@ -43,63 +37,7 @@ float getAngleDithering(in ivec2 pixelPos) {
return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering();
}
const float TWO_PI = 6.28;
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
// Radius relative to ssR
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
ssR = alpha;
return vec2(cos(angle), sin(angle));
}
vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) {
// Radius relative to ssR
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
return vec2(cos(angle), sin(angle), alpha * outerRadius);
}
vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) {
// Derivation:
// mipLevel = floor(log(ssR / MAX_OFFSET));
int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
ivec2 ssOffset = ivec2(ssR * unitOffset);
ivec2 ssP = ssOffset + ssC;
if (bool(isBorderingEnabled())) {
ssP.x = ((ssP.x < 0 || ssP.x >= side.z) ? ssC.x - ssOffset.x : ssP.x);
ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y)) ? ssC.y - ssOffset.y : ssP.y);
}
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
vec3 P;
// We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
// Manually clamp to the texture size because texelFetch bypasses the texture unit
ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1));
P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r;
// Offset to pixel center
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z);
P = evalEyePositionFromZeye(side.x, P.z, tapUV);
return P;
}
float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) {
// Offset on the unit disk, spun for this pixel
float ssR;
vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
ssR *= ssDiskRadius;
// The occluding point in camera space
vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR);
float evalAO(in vec3 C, in vec3 n_C, vec3 Q) {
vec3 v = Q - C;
float vv = dot(v, v);
float vn = dot(v, n_C);
@ -114,7 +52,9 @@ float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssD
void main(void) {
// Pixel Debugged
vec2 cursorUV = getDebugCursorTexcoord();
ivec2 ssC = ivec2(cursorUV * vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())));
vec2 imageSize = getSideImageSize(getResolutionLevel());
vec2 cursorPixelPos = cursorUV * imageSize;
ivec2 ssC = ivec2(cursorPixelPos);
// Pixel being shaded
//ivec2 ssC = ivec2(gl_FragCoord.xy);
@ -126,17 +66,16 @@ void main(void) {
// From now on, ssC is the pixel pos in the side
ssC.x -= side.y;
vec2 fragPos = (vec2(ssC) + vec2(0.5)) / vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel()));
vec2 fragPos = (vec2(ssC) + 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);
// Choose the screen-space sample radius
// proportional to the projected area of the sphere
float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale();
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
vec2 fragToCursor = cursorUV * vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())) - gl_FragCoord.xy;
vec2 fragToCursor = cursorPixelPos - gl_FragCoord.xy;
if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) {
discard;
}
@ -149,18 +88,18 @@ void main(void) {
float keepTapRadius = 2.0;
bool keep = (dot(fragToCursor,fragToCursor) < keepTapRadius);
for (int i = 0; i < getNumSamples(); ++i) {
vec3 tap = getTapLocation(i, randomPatternRotationAngle, outerRadius);
vec2 fragToTap = vec2(ssC) + tap.xy * tap.z - gl_FragCoord.xy;
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize);
// The occluding point in camera space
vec2 fragToTap = vec2(ssC) + tap.xy - gl_FragCoord.xy;
if (dot(fragToTap,fragToTap) < keepTapRadius) {
keep = true;
}
sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle);
vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize);
sum += evalAO(Cp, Cn, Q);
}
if (!keep) {
discard;
}
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
@ -190,4 +129,9 @@ void main(void) {
//outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0);
// outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0);
//outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0);
if (!keep) {
outFragColor = vec4(0.1);
}
}

View file

@ -11,27 +11,12 @@
<@include ssao.slh@>
<$declareAmbientOcclusion()$>
<$declareFetchDepthPyramidMap()$>
<$declareSamplingDisk()$>
<$declarePackOcclusionDepth()$>
const int LOG_MAX_OFFSET = 3;
const int MAX_MIP_LEVEL = 5;
// the depth pyramid texture
uniform sampler2D pyramidMap;
float getZEye(ivec2 pixel) {
return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x;
}
/*
vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) {
// compute the view space position using the depth
// basically manually pick the proj matrix components to do the inverse
float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][0] - frameTransform._projection[side][3][0]) / frameTransform._projection[side][0][0];
float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1];
return vec3(Xe, Ye, Zeye);
}
*/
out vec4 outFragColor;
uniform sampler2D normalMap;
@ -40,18 +25,7 @@ float getAngleDithering(in ivec2 pixelPos) {
// Hash function used in the AlchemyAO paper
return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering();
}
const float TWO_PI = 6.28;
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
// Radius relative to ssR
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
ssR = alpha;
return vec2(cos(angle), sin(angle));
}
/*
vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) {
// Derivation:
// mipLevel = floor(log(ssR / MAX_OFFSET));
@ -77,19 +51,9 @@ vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) {
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z);
P = evalEyePositionFromZeye(side.x, P.z, tapUV);
return P;
}
float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) {
// Offset on the unit disk, spun for this pixel
float ssR;
vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
ssR *= ssDiskRadius;
// The occluding point in camera space
vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR);
}*/
float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) {
vec3 v = Q - C;
float vv = dot(v, v);
float vn = dot(v, n_C);
@ -104,6 +68,8 @@ void main(void) {
// Pixel being shaded
ivec2 ssC = ivec2(gl_FragCoord.xy);
vec2 imageSize = getSideImageSize(getResolutionLevel());
// Fetch the z under the pixel (stereo or not)
float Zeye = getZEye(ssC);
@ -119,8 +85,7 @@ void main(void) {
vec3 Cn = evalEyeNormal(Cp);
// Choose the screen-space sample radius
// proportional to the projected area of the sphere
float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale();
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
// Let's make noise
float randomPatternRotationAngle = getAngleDithering(ssC);
@ -128,7 +93,11 @@ void main(void) {
// Accumulate the Obscurance for each samples
float sum = 0.0;
for (int i = 0; i < getNumSamples(); ++i) {
sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle);
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize);
vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize);
sum += evalAO(Cp, Cn, Q);
}
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());

View file

@ -22,7 +22,9 @@ Column {
model: [
"Radius:radius:2.0:false",
"Level:obscuranceLevel:1.0:false",
"Scale:perspectiveScale:2.0:false",
"Num Taps:numSamples:32:true",
"Taps Spiral:numSpiralTurns:10.0:false",
"Blur Radius:blurRadius:10.0:false",
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])