diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2a3a3f9f4c..3fcf4ef656 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -141,6 +141,10 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture(int resolution return _normalTexture; } +gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { + return _normalTexture; +} + class GaussianDistribution { public: @@ -540,7 +544,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.popProfileRange(); #if SSAO_USE_QUAD_SPLIT - // Build derivative normals pass + // Build face normals pass batch.pushProfileRange("Build Normals"); batch.setViewportTransform(occlusionViewport); batch.setPipeline(buildNormalsPipeline); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 1509cf6492..b0752277c2 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -33,6 +33,7 @@ public: gpu::FramebufferPointer getNormalFramebuffer(int resolutionLevel); gpu::TexturePointer getNormalTexture(int resolutionLevel); + gpu::TexturePointer getNormalTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. bool updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 4a8fad7c6d..3959105829 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -321,6 +321,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return DEFAULT_AMBIENT_OCCLUSION_SHADER; case AmbientOcclusionBlurredMode: return DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER; + case AmbientOcclusionNormalMode: + return DEFAULT_HALF_NORMAL_SHADER; case VelocityMode: return DEFAULT_VELOCITY_SHADER; case CustomMode: @@ -469,6 +471,8 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionTexture()); } else if (_mode == AmbientOcclusionBlurredMode) { batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionBlurredTexture()); + } else if (_mode == AmbientOcclusionNormalMode) { + batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getNormalTexture()); } } const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 0fc006b452..2b8b288a83 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -88,6 +88,7 @@ protected: ScatteringDebugMode, AmbientOcclusionMode, AmbientOcclusionBlurredMode, + AmbientOcclusionNormalMode, VelocityMode, CustomMode, // Needs to stay last diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 17ac229805..56566c9b6f 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -223,7 +223,7 @@ vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { } int evalMipFromRadius(float radius) { - const int LOG_MAX_OFFSET = 2; + const int LOG_MAX_OFFSET = 1; const int MAX_MIP_LEVEL = 5; return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } @@ -231,10 +231,8 @@ int evalMipFromRadius(float radius) { vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageSize) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); - // 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 vec2 tapUV = (tapSidePixelPos + vec2(0.5)) / sideImageSize; - vec2 fetchUV = mix(tapUV, vec2((tapUV.x + getStereoSide(side)) * 0.5, tapUV.y), isStereoFromInfo(side)); + vec2 fetchUV = mix(tapUV, vec2((tapUV.x + getStereoSide(side)) * 0.5, tapUV.y), isStereo()); vec4 P; P.xy = tapUV; @@ -250,21 +248,21 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, ivec2 return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } -vec3 getMinDiff(vec3 centralPoint, vec3 offsetPoint0, vec3 offsetPoint1) { - vec3 delta0 = offsetPoint0 - centralPoint; - vec3 delta1 = centralPoint - offsetPoint1; +vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { + vec3 delta0 = offsetPointPos - centralPoint; + vec3 delta1 = centralPoint - offsetPointNeg; return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1; } -vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPositionES, ivec2 depthTextureScale, vec2 sideImageSize) { +vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, ivec2 depthTextureScale, vec2 sideImageSize) { vec2 uvScale = vec2(1.0) / (sideImageSize * depthTextureScale); - vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1,0), uvScale); - vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1,0), uvScale); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0,1), uvScale); - vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0,-1), uvScale); + vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1, 0), uvScale); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, 1), uvScale); + vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1, 0), uvScale); + vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, -1), uvScale); - vec3 fragPositionDx = getMinDiff(fragPositionES, fragPositionDxPos, fragPositionDxNeg); - vec3 fragPositionDy = getMinDiff(fragPositionES, fragPositionDyPos, fragPositionDyNeg); + vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); + vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); return normalize( cross(fragPositionDx, fragPositionDy) ); } @@ -287,31 +285,30 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t float vv = dot(v, v); float vn = dot(v, centerNormal); - // Fall off function as recommended in SSAO paper + // Falloff function as recommended in SSAO paper const float epsilon = 0.01; float f = max(getRadius2() - vv, 0.0); return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0); } float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { - const float epsilon = 0.01; + const float epsilon = 0.001; vec3 deltaVec = tapPositionES - fragPositionES; float distance = length(deltaVec); - float cosHorizonAngle = 0.0; + float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); - cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale()); cosHorizonAngle *= radiusFalloff; - return cosHorizonAngle; } <@func computeHorizon()@> vec2 tapSidePixelPos = tapPixelOffset + shadedPixelPos; - if (tapSidePixelPos.x<0 && tapSidePixelPos.y<0 && tapSidePixelPos.x>=sideImageSize.x && tapSidePixelPos.y>=sideImageSize.y) { + if (tapSidePixelPos.x<0 || tapSidePixelPos.y<0 || tapSidePixelPos.x>=sideImageSize.x || tapSidePixelPos.y>=sideImageSize.y) { + // Early exit because we've hit the borders of the frame break; } vec4 tapUVZ_mip = fetchTap(side, tapSidePixelPos, radius, sideImageSize); @@ -426,7 +423,7 @@ float fetchOcclusion(vec2 coords) { return raw.x; } -const float BLUR_EDGE_DISTANCE_SCALE = 300.0; +const float BLUR_EDGE_DISTANCE_SCALE = 1000.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { ivec2 tapOffset = <$axis$> * r; diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index f21a529807..f3af324455 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -40,7 +40,6 @@ void main(void) { // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); - vec3 absFragNormalES = abs(fragNormalES); - + outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); } diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 8a4a8f0622..1e1e6055f8 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -202,6 +202,7 @@ Rectangle { ListElement { text: "Debug Scattering"; color: "White" } ListElement { text: "Ambient Occlusion"; color: "White" } ListElement { text: "Ambient Occlusion Blurred"; color: "White" } + ListElement { text: "Ambient Occlusion Normal"; color: "White" } ListElement { text: "Velocity"; color: "White" } ListElement { text: "Custom"; color: "White" } }