# Screen-space ambient occlusion for volume rendering

**URL:** <https://discourse.slicer.org/t/screen-space-ambient-occlusion-for-volume-rendering/32323>\
**Category:** Development\
**Tags:** volume-rendering\
**Created:** [October 19, 2023, 9:16am UTC](https://discourse.slicer.org/t/screen-space-ambient-occlusion-for-volume-rendering/32323 "2023-10-19T09:16:17Z")\
**Posts on this page:** 1\
**Showing post:** 7

<div class="post-metadata">

**Author:** ![LucasGandel](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lucasgandel/32/18202_2.png) [@LucasGandel](https://discourse.slicer.org/u/LucasGandel)\
**Post date:** [October 19, 2023, 2:27pm UTC](https://discourse.slicer.org/t/screen-space-ambient-occlusion-for-volume-rendering/32323/7 "2023-10-19T14:27:31Z")

</div>

As I probably won’t have time to go further before tonight, and can’t wait to see if this performs well on your side. Here is a quick way to try it:

1. VTK changes required: [This commit](https://gitlab.kitware.com/LucasGandelKitware/vtk/-/commit/586e173991b60aa6fa24dc261099f76d7cdfea70) from the volume-ssao branch
2. The following shader replacement on the mapper:

```auto
  volume->GetProperty()->ShadeOn();

  volume->GetShaderProperty()->AddFragmentShaderReplacement("//VTK::ComputeLighting::Dec", true,
    "vec3 g_dataNormal; \n"\
    "//VTK::ComputeLighting::Dec\n",
    false);
  volume->GetShaderProperty()->AddFragmentShaderReplacement("//VTK::RenderToImage::Dec", true,
    "vec3 l_opaqueFragNormal;\n"
    "vec3 l_opaqueFragPos;\n"
    "bool l_updateDepth;\n",
    false);

  volume->GetShaderProperty()->AddFragmentShaderReplacement("//VTK::RenderToImage::Init", true,
    "\
    \n l_opaqueFragPos = vec3(-1.0);\
    \n l_updateDepth = true;",
    false);

  volume->GetShaderProperty()->AddFragmentShaderReplacement("//VTK::RenderToImage::Impl", true,
    "\
    \n if(!g_skip && g_srcColor.a > 0.0 && l_updateDepth)\
    \n {\
    \n l_opaqueFragPos = g_dataPos;\
    \n l_opaqueFragNormal = g_dataNormal;\
    \n l_updateDepth = false;\
    \n }",
    false);

  volume->GetShaderProperty()->AddFragmentShaderReplacement("//VTK::RenderToImage::Exit", true,
    "\
    \n if (l_opaqueFragPos == vec3(-1.0))\
    \n {\
\n gl_FragDepth = 1.0; \
\n gl_FragData[1] = gl_FragData[1]; \
    \n }\
    \n else\
    \n {\
    \n vec4 depthValue = in_projectionMatrix * in_modelViewMatrix *\
    \n in_volumeMatrix[0] * in_textureDatasetMatrix[0] *\
    \n vec4(l_opaqueFragPos, 1.0);\
    \n depthValue /= depthValue.w;\
    \n gl_FragDepth = 0.5 * (gl_DepthRange.far - gl_DepthRange.near) * depthValue.z + 0.5 * (gl_DepthRange.far + gl_DepthRange.near);\
    \n gl_FragData[1] = in_modelViewMatrix * in_volumeMatrix[0] * in_textureDatasetMatrix[0] * vec4(l_opaqueFragPos, 1.0);\
    \n gl_FragData[2] = vec4(l_opaqueFragNormal, 0.0);\
    \n }",
    false);

```

Important:  
Shading must be turned ON otherwise the shader fails to compile. Other non-default options have not been tested.  
The VTK commit above works around a problem with FBOs when the SSAO pass is activated, by commenting the depth buffer blit that is required for surfaces to occlude the volume. This should be fixed later.

---

_[View the full topic](https://discourse.slicer.org/t/screen-space-ambient-occlusion-for-volume-rendering/32323)._
