Unified · Split
| @@ -52,7 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); · 51 unmodified lines | |||
| 52 | 52 | ||
| 53 | var resizing = false; | 53 | var resizing = false; |
| 54 | var previousMode = Settings.getValue(SETTINGS_KEY, -1); | 54 | var previousMode = Settings.getValue(SETTINGS_KEY, -1); |
| 55 | previousMode = 1; | 55 | previousMode = 4; // FIXME: just for debug purpose |
| 56 | Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); | 56 | Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); |
| 57 | Render.deferredDebugMode = previousMode; | 57 | Render.deferredDebugMode = previousMode; |
| 58 | Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size | 58 | Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size |
| @@ -80,7 +80,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { · 79 unmodified lines | |||
| 80 | slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); | 80 | slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); |
| 81 | slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); | 81 | slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); |
| 82 | slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); | 82 | slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); |
| 83 | 83 | ||
| 84 | slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), AmbientOcclusionEffect_PyramidMapSlot + 1)); | ||
| 84 | gpu::Shader::makeProgram(*program, slotBindings); | 85 | gpu::Shader::makeProgram(*program, slotBindings); |
| 85 | 86 | ||
| 86 | 87 | ||
| @@ -90,7 +91,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { · 3 unmodified lines | |||
| 90 | state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); | 91 | state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); |
| 91 | 92 | ||
| 92 | state->setColorWriteMask(true, true, true, false); | 93 | state->setColorWriteMask(true, true, true, false); |
| 93 | 94 | //state->setColorWriteMask(true, true, true, true); | |
| 95 | |||
| 94 | // Good to go add the brand new pipeline | 96 | // Good to go add the brand new pipeline |
| 95 | _occlusionPipeline = gpu::Pipeline::create(program, state); | 97 | _occlusionPipeline = gpu::Pipeline::create(program, state); |
| 96 | } | 98 | } |
| @@ -147,83 +149,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { · 50 unmodified lines | |||
| 147 | 149 | ||
| 148 | // Good to go add the brand new pipeline | 150 | // Good to go add the brand new pipeline |
| 149 | _vBlurPipeline = gpu::Pipeline::create(program, state); | 151 | _vBlurPipeline = gpu::Pipeline::create(program, state); |
| 150 | |||
| 151 | const char blur_frag[] = R"SCRIBE(#version 410 core | ||
| 152 | // | ||
| 153 | // Created by Sam Gateau on 12/31/2015 | ||
| 154 | // Copyright 2015 High Fidelity, Inc. | ||
| 155 | // | ||
| 156 | // Distributed under the Apache License, Version 2.0. | ||
| 157 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 158 | // | ||
| 159 | |||
| 160 | struct AmbientOcclusionParams { | ||
| 161 | vec4 _clipInfo; | ||
| 162 | mat4 _projection; | ||
| 163 | vec4 _radius_s0_s1_s2; | ||
| 164 | }; | ||
| 165 | |||
| 166 | uniform ambientOcclusionParamsBuffer { | ||
| 167 | AmbientOcclusionParams params; | ||
| 168 | }; | ||
| 169 | |||
| 170 | float evalZeyeFromZdb(float depth) { | ||
| 171 | return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); | ||
| 172 | } | ||
| 173 | |||
| 174 | // the depth texture | ||
| 175 | uniform sampler2D depthMap; | ||
| 176 | |||
| 177 | in vec2 varTexCoord0; | ||
| 178 | out vec4 outFragColor; | ||
| 179 | |||
| 180 | ivec2 ssC = ivec2(gl_FragCoord.xy); | ||
| 181 | |||
| 182 | vec4 temp = texelFetch(source, ssC, 0); | ||
| 183 | |||
| 184 | keyPassThrough = temp.KEY_COMPONENTS; | ||
| 185 | float key = unpackKey(keyPassThrough); | ||
| 186 | |||
| 187 | VALUE_TYPE sum = temp.VALUE_COMPONENTS; | ||
| 188 | |||
| 189 | if (key == 1.0) { | ||
| 190 | // Sky pixel (if you aren't using depth keying, disable this test) | ||
| 191 | result = sum; | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | |||
| 195 | // Base weight for depth falloff. Increase this for more blurriness, | ||
| 196 | // decrease it for better edge discrimination | ||
| 197 | float BASE = gaussian[0]; | ||
| 198 | float totalWeight = BASE; | ||
| 199 | sum *= totalWeight; | ||
| 200 | |||
| 201 | |||
| 202 | for (int r = -R; r <= R; ++r) { | ||
| 203 | // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, | ||
| 204 | // so the IF statement has no runtime cost | ||
| 205 | if (r != 0) { | ||
| 206 | temp = texelFetch(source, ssC + axis * (r * SCALE), 0); | ||
| 207 | float tapKey = unpackKey(temp.KEY_COMPONENTS); | ||
| 208 | VALUE_TYPE value = temp.VALUE_COMPONENTS; | ||
| 209 | |||
| 210 | // spatial domain: offset gaussian tap | ||
| 211 | float weight = 0.3 + gaussian[abs(r)]; | ||
| 212 | |||
| 213 | // range domain (the "bilateral" weight). As depth difference increases, decrease weight. | ||
| 214 | weight *= max(0.0, 1.0 | ||
| 215 | - (EDGE_SHARPNESS * 2000.0) * abs(tapKey - key) | ||
| 216 | ); | ||
| 217 | |||
| 218 | sum += value * weight; | ||
| 219 | totalWeight += weight; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | const float epsilon = 0.0001; | ||
| 224 | result = sum / (totalWeight + epsilon); | ||
| 225 | |||
| 226 | )SCRIBE"; | ||
| 227 | } | 152 | } |
| 228 | return _vBlurPipeline; | 153 | return _vBlurPipeline; |
| 229 | } | 154 | } |
| @@ -346,6 +271,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext · 116 unmodified lines | |||
| 346 | RenderArgs* args = renderContext->getArgs(); | 271 | RenderArgs* args = renderContext->getArgs(); |
| 347 | auto framebufferCache = DependencyManager::get<FramebufferCache>(); | 272 | auto framebufferCache = DependencyManager::get<FramebufferCache>(); |
| 348 | auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); | 273 | auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); |
| 274 | auto normalBuffer = framebufferCache->getDeferredNormalTexture(); | ||
| 349 | auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); | 275 | auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); |
| 350 | auto occlusionFBO = framebufferCache->getOcclusionFramebuffer(); | 276 | auto occlusionFBO = framebufferCache->getOcclusionFramebuffer(); |
| 351 | auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer(); | 277 | auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer(); |
| @@ -366,7 +292,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext · 14 unmodified lines | |||
| 366 | 292 | ||
| 367 | setClipInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); | 293 | setClipInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); |
| 368 | _parametersBuffer.edit<Parameters>()._projection = monoProjMat; | 294 | _parametersBuffer.edit<Parameters>()._projection = monoProjMat; |
| 369 | 295 | _parametersBuffer.edit<Parameters>()._pixelInfo = args->_viewport; | |
| 370 | 296 | ||
| 371 | auto pyramidPipeline = getPyramidPipeline(); | 297 | auto pyramidPipeline = getPyramidPipeline(); |
| 372 | auto occlusionPipeline = getOcclusionPipeline(); | 298 | auto occlusionPipeline = getOcclusionPipeline(); |
| @@ -404,9 +330,13 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext · 31 unmodified lines | |||
| 404 | 330 | ||
| 405 | // Occlusion pass | 331 | // Occlusion pass |
| 406 | batch.setPipeline(occlusionPipeline); | 332 | batch.setPipeline(occlusionPipeline); |
| 333 | |||
| 334 | // batch.setFramebuffer(occlusionFinalFBO); | ||
| 407 | batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); | 335 | batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); |
| 336 | batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, normalBuffer); | ||
| 408 | batch.draw(gpu::TRIANGLE_STRIP, 4); | 337 | batch.draw(gpu::TRIANGLE_STRIP, 4); |
| 409 | 338 | batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, gpu::TexturePointer()); | |
| 339 | |||
| 410 | // Blur 1 pass | 340 | // Blur 1 pass |
| 411 | batch.setFramebuffer(occlusionBlurredFBO); | 341 | batch.setFramebuffer(occlusionBlurredFBO); |
| 412 | batch.setPipeline(firstHBlurPipeline); | 342 | batch.setPipeline(firstHBlurPipeline); |
| @@ -34,6 +34,7 @@ private: · 33 unmodified lines | |||
| 34 | // Class describing the uniform buffer with all the parameters common to the AO shaders | 34 | // Class describing the uniform buffer with all the parameters common to the AO shaders |
| 35 | class Parameters { | 35 | class Parameters { |
| 36 | public: | 36 | public: |
| 37 | glm::vec4 _pixelInfo; | ||
| 37 | glm::vec4 _clipInfo; | 38 | glm::vec4 _clipInfo; |
| 38 | glm::mat4 _projection; | 39 | glm::mat4 _projection; |
| 39 | glm::vec4 _radius_radius2_InvRadius6_s2{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 0.0 }; | 40 | glm::vec4 _radius_radius2_InvRadius6_s2{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 0.0 }; |
| @@ -68,11 +68,14 @@ struct DeferredFragment { · 67 unmodified lines | |||
| 68 | vec4 position; | 68 | vec4 position; |
| 69 | vec3 normal; | 69 | vec3 normal; |
| 70 | vec3 diffuse; | 70 | vec3 diffuse; |
| 71 | float opacity; | 71 | float obscurance; |
| 72 | vec3 specular; | 72 | vec3 specular; |
| 73 | float gloss; | 73 | float gloss; |
| 74 | int mode; | ||
| 74 | }; | 75 | }; |
| 75 | 76 | ||
| 77 | const int LIGHT_MAPPED = 1; | ||
| 78 | |||
| 76 | DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) { | 79 | DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) { |
| 77 | DeferredFragment frag; | 80 | DeferredFragment frag; |
| 78 | frag.depthVal = texture(depthMap, texcoord).r; | 81 | frag.depthVal = texture(depthMap, texcoord).r; |
| @@ -88,11 +91,16 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec · 9 unmodified lines | |||
| 88 | } | 91 | } |
| 89 | frag.position = evalEyePositionFromZ(deferredTransform, frag.depthVal, texcoord); | 92 | frag.position = evalEyePositionFromZ(deferredTransform, frag.depthVal, texcoord); |
| 90 | 93 | ||
| 91 | // Unpack the normal from the map | 94 | // Unpack the normal from the map |
| 92 | frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); | 95 | frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); |
| 96 | |||
| 97 | frag.mode = 0; | ||
| 98 | if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { | ||
| 99 | frag.mode = LIGHT_MAPPED; | ||
| 100 | } | ||
| 93 | 101 | ||
| 94 | frag.diffuse = frag.diffuseVal.xyz; | 102 | frag.diffuse = frag.diffuseVal.xyz; |
| 95 | frag.opacity = frag.normalVal.w; | 103 | frag.obscurance = frag.diffuseVal.w; |
| 96 | frag.specular = frag.specularVal.xyz; | 104 | frag.specular = frag.specularVal.xyz; |
| 97 | frag.gloss = frag.specularVal.w; | 105 | frag.gloss = frag.specularVal.w; |
| 98 | 106 | ||
| @@ -105,7 +105,7 @@ void FramebufferCache::createPrimaryFramebuffer() { · 104 unmodified lines | |||
| 105 | 105 | ||
| 106 | 106 | ||
| 107 | // For AO: | 107 | // For AO: |
| 108 | _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB), width, height, smoothSampler)); | 108 | _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, smoothSampler)); |
| 109 | _depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); | 109 | _depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); |
| 110 | _depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture); | 110 | _depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture); |
| 111 | _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); | 111 | _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); |
| @@ -27,7 +27,7 @@ void main(void) { · 26 unmodified lines | |||
| 27 | DeferredTransform deferredTransform = getDeferredTransform(); | 27 | DeferredTransform deferredTransform = getDeferredTransform(); |
| 28 | DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); | 28 | DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); |
| 29 | 29 | ||
| 30 | if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { | 30 | if (frag.mode == LIGHT_MAPPED) { |
| 31 | vec3 color = evalLightmappedColor( | 31 | vec3 color = evalLightmappedColor( |
| 32 | deferredTransform.viewInverse, | 32 | deferredTransform.viewInverse, |
| 33 | 1.0, | 33 | 1.0, |
| @@ -38,7 +38,7 @@ void main(void) { · 4 unmodified lines | |||
| 38 | } else { | 38 | } else { |
| 39 | vec3 color = evalAmbienSphereGlobalColor( | 39 | vec3 color = evalAmbienSphereGlobalColor( |
| 40 | deferredTransform.viewInverse, | 40 | deferredTransform.viewInverse, |
| 41 | 1.0, | 41 | frag.obscurance, |
| 42 | frag.position.xyz, | 42 | frag.position.xyz, |
| 43 | frag.normal, | 43 | frag.normal, |
| 44 | frag.diffuse, | 44 | frag.diffuse, |
| @@ -28,7 +28,7 @@ void main(void) { · 27 unmodified lines | |||
| 28 | DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); | 28 | DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); |
| 29 | 29 | ||
| 30 | // Light mapped or not ? | 30 | // Light mapped or not ? |
| 31 | if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { | 31 | if (frag.mode == LIGHT_MAPPED) { |
| 32 | vec3 color = evalLightmappedColor( | 32 | vec3 color = evalLightmappedColor( |
| 33 | deferredTransform.viewInverse, | 33 | deferredTransform.viewInverse, |
| 34 | 1.0, | 34 | 1.0, |
| @@ -39,7 +39,7 @@ void main(void) { · 4 unmodified lines | |||
| 39 | } else { | 39 | } else { |
| 40 | vec3 color = evalAmbienGlobalColor( | 40 | vec3 color = evalAmbienGlobalColor( |
| 41 | deferredTransform.viewInverse, | 41 | deferredTransform.viewInverse, |
| 42 | 1.0, | 42 | frag.obscurance, |
| 43 | frag.position.xyz, | 43 | frag.position.xyz, |
| 44 | frag.normal, | 44 | frag.normal, |
| 45 | frag.diffuse, | 45 | frag.diffuse, |
| @@ -28,7 +28,7 @@ void main(void) { · 27 unmodified lines | |||
| 28 | DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); | 28 | DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); |
| 29 | 29 | ||
| 30 | // Light mapped or not ? | 30 | // Light mapped or not ? |
| 31 | if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { | 31 | if (frag.mode == LIGHT_MAPPED) { |
| 32 | vec3 color = evalLightmappedColor( | 32 | vec3 color = evalLightmappedColor( |
| 33 | deferredTransform.viewInverse, | 33 | deferredTransform.viewInverse, |
| 34 | 1.0, | 34 | 1.0, |
| @@ -39,7 +39,7 @@ void main(void) { · 4 unmodified lines | |||
| 39 | } else { | 39 | } else { |
| 40 | vec3 color = evalSkyboxGlobalColor( | 40 | vec3 color = evalSkyboxGlobalColor( |
| 41 | deferredTransform.viewInverse, | 41 | deferredTransform.viewInverse, |
| 42 | 1.0, | 42 | frag.obscurance, |
| 43 | frag.position.xyz, | 43 | frag.position.xyz, |
| 44 | frag.normal, | 44 | frag.normal, |
| 45 | frag.diffuse, | 45 | frag.diffuse, |
| @@ -11,9 +11,28 @@ · 10 unmodified lines | |||
| 11 | <@if not SSAO_SLH@> | 11 | <@if not SSAO_SLH@> |
| 12 | <@def SSAO_SLH@> | 12 | <@def SSAO_SLH@> |
| 13 | 13 | ||
| 14 | <@func declarePackOcclusionDepth()@> | ||
| 15 | |||
| 16 | const float FAR_PLANE_Z = -300.0; | ||
| 17 | |||
| 18 | float CSZToDephtKey(float z) { | ||
| 19 | return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0); | ||
| 20 | } | ||
| 21 | vec3 packOcclusionDepth(float occlusion, float depth) { | ||
| 22 | // Round to the nearest 1/256.0 | ||
| 23 | float temp = floor(depth * 256.0); | ||
| 24 | return vec3(occlusion, temp * (1.0 / 256.0), depth * 256.0 - temp); | ||
| 25 | } | ||
| 26 | vec2 unpackOcclusionDepth(vec3 packed) { | ||
| 27 | float z = packed.y * (256.0 / 257.0) + packed.z * (1.0 / 257.0); | ||
| 28 | return vec2(packed.x, z); | ||
| 29 | } | ||
| 30 | <@endfunc@> | ||
| 31 | |||
| 14 | <@func declareAmbientOcclusion()@> | 32 | <@func declareAmbientOcclusion()@> |
| 15 | 33 | ||
| 16 | struct AmbientOcclusionParams { | 34 | struct AmbientOcclusionParams { |
| 35 | vec4 _pixelInfo; | ||
| 17 | vec4 _clipInfo; | 36 | vec4 _clipInfo; |
| 18 | mat4 _projection; | 37 | mat4 _projection; |
| 19 | vec4 _radius_radius2_InvRadius6_s2; | 38 | vec4 _radius_radius2_InvRadius6_s2; |
| @@ -23,8 +42,11 @@ uniform ambientOcclusionParamsBuffer { · 3 unmodified lines | |||
| 23 | AmbientOcclusionParams params; | 42 | AmbientOcclusionParams params; |
| 24 | }; | 43 | }; |
| 25 | 44 | ||
| 45 | vec2 getWidthHeight() { | ||
| 46 | return params._pixelInfo.zw; | ||
| 47 | } | ||
| 26 | float getProjScale() { | 48 | float getProjScale() { |
| 27 | return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0 | 49 | return getWidthHeight().y * params._projection[1][1] * 0.5; |
| 28 | } | 50 | } |
| 29 | 51 | ||
| 30 | float getRadius() { | 52 | float getRadius() { |
| @@ -50,8 +72,77 @@ vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { · 19 unmodified lines | |||
| 50 | } | 72 | } |
| 51 | 73 | ||
| 52 | vec3 evalEyeNormal(vec3 C) { | 74 | vec3 evalEyeNormal(vec3 C) { |
| 53 | return normalize(cross(dFdy(C), dFdx(C))); | 75 | //return normalize(cross(dFdy(C), dFdx(C))); |
| 76 | return normalize(cross(dFdx(C), dFdy(C))); | ||
| 54 | } | 77 | } |
| 78 | |||
| 79 | <@endfunc@> | ||
| 80 | |||
| 81 | <@func declareBlurPass(axis)@> | ||
| 82 | |||
| 83 | <$declarePackOcclusionDepth()$> | ||
| 84 | |||
| 85 | // the source occlusion texture | ||
| 86 | uniform sampler2D occlusionMap; | ||
| 87 | |||
| 88 | vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) { | ||
| 89 | raw = texelFetch(occlusionMap, coords, 0).xyz; | ||
| 90 | return unpackOcclusionDepth(raw); | ||
| 91 | } | ||
| 92 | |||
| 93 | vec2 fetchOcclusionDepth(ivec2 coords) { | ||
| 94 | return unpackOcclusionDepth(texelFetch(occlusionMap, coords, 0).xyz); | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | const int BLUR_RADIUS = 4; | ||
| 99 | const int RADIUS_SCALE = 2; | ||
| 100 | const float EDGE_SHARPNESS = 1.0; | ||
| 101 | |||
| 102 | const float gaussian[BLUR_RADIUS + 1] = | ||
| 103 | // float[](0.356642, 0.239400, 0.072410, 0.009869); // R = 2 | ||
| 104 | // float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // R = 3 | ||
| 105 | float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // R = 4 | ||
| 106 | // float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // R = 5.0 | ||
| 107 | |||
| 108 | vec3 getBlurredOcclusion(vec2 coord) { | ||
| 109 | ivec2 ssC = ivec2(coord); | ||
| 110 | |||
| 111 | vec3 rawSample; | ||
| 112 | vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample); | ||
| 113 | float key = occlusionDepth.y; | ||
| 114 | float sum = occlusionDepth.x; | ||
| 115 | |||
| 116 | // Base weight for depth falloff. Increase this for more blurriness, | ||
| 117 | // decrease it for better edge discrimination | ||
| 118 | float BASE = gaussian[0]; | ||
| 119 | float totalWeight = BASE; | ||
| 120 | sum *= totalWeight; | ||
| 121 | |||
| 122 | for (int r = -BLUR_RADIUS; r <= BLUR_RADIUS; ++r) { | ||
| 123 | // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, | ||
| 124 | // so the IF statement has no runtime cost | ||
| 125 | if (r != 0) { | ||
| 126 | vec2 tapOZ = fetchOcclusionDepth(ssC + <$axis$> * (r * RADIUS_SCALE)); | ||
| 127 | |||
| 128 | // spatial domain: offset gaussian tap | ||
| 129 | float weight = 0.3 + gaussian[abs(r)]; | ||
| 130 | |||
| 131 | // range domain (the "bilateral" weight). As depth difference increases, decrease weight. | ||
| 132 | weight *= max(0.0, 1.0 - (EDGE_SHARPNESS * 2000.0) * abs(tapOZ.y - key)); | ||
| 133 | |||
| 134 | sum += tapOZ.x * weight; | ||
| 135 | totalWeight += weight; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | const float epsilon = 0.0001; | ||
| 140 | float result = sum / (totalWeight + epsilon); | ||
| 141 | |||
| 142 | rawSample.x = result; | ||
| 143 | return rawSample; | ||
| 144 | } | ||
| 145 | |||
| 55 | <@endfunc@> | 146 | <@endfunc@> |
| 56 | 147 | ||
| 57 | 148 | ||
| @@ -10,14 +10,14 @@ · 9 unmodified lines | |||
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | <@include ssao.slh@> | 12 | <@include ssao.slh@> |
| 13 | <$declareAmbientOcclusion()$> | ||
| 14 | 13 | ||
| 15 | // the depth texture | 14 | const ivec2 horizontal = ivec2(1,0); |
| 16 | uniform sampler2D occlusionMap; | 15 | <$declareBlurPass(horizontal)$> |
| 16 | |||
| 17 | 17 | ||
| 18 | in vec2 varTexCoord0; | 18 | in vec2 varTexCoord0; |
| 19 | out vec4 outFragColor; | 19 | out vec4 outFragColor; |
| 20 | 20 | ||
| 21 | void main(void) { | 21 | void main(void) { |
| 22 | outFragColor = texture(occlusionMap, varTexCoord0); | 22 | outFragColor = vec4(getBlurredOcclusion(gl_FragCoord.xy), 1.0); |
| 23 | } | 23 | } |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | <@include ssao.slh@> | 12 | <@include ssao.slh@> |
| 13 | <$declareAmbientOcclusion()$> | 13 | <$declareAmbientOcclusion()$> |
| 14 | <$declarePackOcclusionDepth()$> | ||
| 14 | 15 | ||
| 15 | const int NUM_SAMPLES = 11; | 16 | const int NUM_SAMPLES = 11; |
| 16 | const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES); | 17 | const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES); |
| @@ -21,34 +22,15 @@ const int MAX_MIP_LEVEL = 5; · 4 unmodified lines | |||
| 21 | // the depth pyramid texture | 22 | // the depth pyramid texture |
| 22 | uniform sampler2D pyramidMap; | 23 | uniform sampler2D pyramidMap; |
| 23 | 24 | ||
| 24 | float getZeye(vec2 texcoord) { | ||
| 25 | return -texture(pyramidMap, texcoord, 0).x; | ||
| 26 | } | ||
| 27 | |||
| 28 | vec3 evalEyePosition(vec2 texcoord) { | 25 | vec3 evalEyePosition(vec2 texcoord) { |
| 29 | float Zeye = getZeye(texcoord); | 26 | float Zeye = -texture(pyramidMap, texcoord, 0).x; |
| 30 | return evalEyePositionFromZeye(Zeye, texcoord); | 27 | return evalEyePositionFromZeye(Zeye, texcoord); |
| 31 | } | 28 | } |
| 32 | 29 | ||
| 33 | in vec2 varTexCoord0; | 30 | in vec2 varTexCoord0; |
| 34 | out vec4 outFragColor; | 31 | out vec4 outFragColor; |
| 35 | 32 | ||
| 36 | /** Used for packing Z into the GB channels */ | 33 | uniform sampler2D normalMap; |
| 37 | float CSZToKey(float z) { | ||
| 38 | return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0); | ||
| 39 | } | ||
| 40 | |||
| 41 | /** Used for packing Z into the GB channels */ | ||
| 42 | void packKey(float key, out vec2 p) { | ||
| 43 | // Round to the nearest 1/256.0 | ||
| 44 | float temp = floor(key * 256.0); | ||
| 45 | |||
| 46 | // Integer part | ||
| 47 | p.x = temp * (1.0 / 256.0); | ||
| 48 | |||
| 49 | // Fractional part | ||
| 50 | p.y = key * 256.0 - temp; | ||
| 51 | } | ||
| 52 | 34 | ||
| 53 | vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ | 35 | vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ |
| 54 | // Radius relative to ssR | 36 | // Radius relative to ssR |
| @@ -76,7 +58,7 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { · 21 unmodified lines | |||
| 76 | // Offset to pixel center | 58 | // Offset to pixel center |
| 77 | //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); | 59 | //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); |
| 78 | 60 | ||
| 79 | vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0); | 61 | vec2 tapUV = (vec2(ssP) + vec2(0.5)) / getWidthHeight(); |
| 80 | P = evalEyePositionFromZeye(P.z, tapUV); | 62 | P = evalEyePositionFromZeye(P.z, tapUV); |
| 81 | return P; | 63 | return P; |
| 82 | } | 64 | } |
| @@ -128,14 +110,11 @@ void main(void) { · 45 unmodified lines | |||
| 128 | 110 | ||
| 129 | vec3 Cp = evalEyePosition(varTexCoord0); | 111 | vec3 Cp = evalEyePosition(varTexCoord0); |
| 130 | 112 | ||
| 131 | // packKey(CSZToKey(Cp.z), bilateralKey); | ||
| 132 | |||
| 133 | // Hash function used in the HPG12 AlchemyAO paper | 113 | // Hash function used in the HPG12 AlchemyAO paper |
| 134 | float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; | 114 | float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; |
| 135 | //float randomPatternRotationAngle = 0; | ||
| 136 | |||
| 137 | 115 | ||
| 138 | vec3 Cn = evalEyeNormal(Cp); | 116 | vec3 Cn = evalEyeNormal(Cp); |
| 117 | // vec3 Cn = normalize((texelFetch(normalMap, ssC, 0).xyz * 2.0) - vec3(1.0)); | ||
| 139 | 118 | ||
| 140 | // Choose the screen-space sample radius | 119 | // Choose the screen-space sample radius |
| 141 | // proportional to the projected area of the sphere | 120 | // proportional to the projected area of the sphere |
| @@ -143,20 +122,20 @@ void main(void) { · 1 unmodified line | |||
| 143 | 122 | ||
| 144 | float sum = 0.0; | 123 | float sum = 0.0; |
| 145 | for (int i = 0; i < NUM_SAMPLES; ++i) { | 124 | for (int i = 0; i < NUM_SAMPLES; ++i) { |
| 146 | sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); | 125 | sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); |
| 147 | } | 126 | } |
| 148 | 127 | ||
| 149 | float A = max(0.0, 1.0 - sum * getInvRadius6() * 5.0 * INV_NUM_SAMPLES); | 128 | float A = max(0.0, 1.0 - sum * getInvRadius6() * 5.0 * INV_NUM_SAMPLES); |
| 150 | 129 | ||
| 151 | // Bilateral box-filter over a quad for free, respecting depth edges | 130 | // Bilateral box-filter over a quad for free, respecting depth edges |
| 152 | // (the difference that this makes is subtle) | 131 | // (the difference that this makes is subtle) |
| 153 | if (abs(dFdx(Cp.z)) < 0.02) { | 132 | /*if (abs(dFdx(Cp.z)) < 0.02) { |
| 154 | A -= dFdx(A) * ((ssC.x & 1) - 0.5); | 133 | A -= dFdx(A) * ((ssC.x & 1) - 0.5); |
| 155 | } | 134 | } |
| 156 | if (abs(dFdy(Cp.z)) < 0.02) { | 135 | if (abs(dFdy(Cp.z)) < 0.02) { |
| 157 | A -= dFdy(A) * ((ssC.y & 1) - 0.5); | 136 | A -= dFdy(A) * ((ssC.y & 1) - 0.5); |
| 158 | } | 137 | }*/ |
| 159 | |||
| 160 | 138 | ||
| 161 | outFragColor = vec4(A, debugValue(Cn.y, 10)); | 139 | outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); |
| 140 | //outFragColor = vec4(0.5 * (Cn + vec3(1.0)), A); | ||
| 162 | } | 141 | } |
| @@ -8,16 +8,15 @@ · 7 unmodified lines | |||
| 8 | // Distributed under the Apache License, Version 2.0. | 8 | // Distributed under the Apache License, Version 2.0. |
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | |||
| 12 | <@include ssao.slh@> | 11 | <@include ssao.slh@> |
| 13 | <$declareAmbientOcclusion()$> | ||
| 14 | 12 | ||
| 15 | // the depth texture | 13 | const ivec2 vertical = ivec2(0,1); |
| 16 | uniform sampler2D occlusionMap; | 14 | <$declareBlurPass(vertical)$> |
| 17 | 15 | ||
| 18 | in vec2 varTexCoord0; | 16 | in vec2 varTexCoord0; |
| 19 | out vec4 outFragColor; | 17 | out vec4 outFragColor; |
| 20 | 18 | ||
| 21 | void main(void) { | 19 | void main(void) { |
| 22 | outFragColor = vec4(0.0, 0.0, 0.0, texture(occlusionMap, varTexCoord0).x); | 20 | float occlusion = getBlurredOcclusion(gl_FragCoord.xy).x; |
| 21 | outFragColor = vec4(0.0, 0.0, 0.0, occlusion); | ||
| 23 | } | 22 | } |