Guest User

Tyler Howard - SSAO Example Code

a guest
Mar 4th, 2013
38
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //Tyler Howard
  2. //
  3. //Screen Space Ambient Occlusion
  4. //
  5. //For the sake of explanation and brevity, this file contains relevant
  6. //excerpts from multiple files.
  7. //
  8. //
  9. //Basic overview:
  10. //
  11. //To obtain a screen-space ambient occlusion effect,
  12. //we need to make multiple rendering passes for the post-process
  13. //shader to eventually do its work.
  14. //
  15. //Pass 1 is a render of the scene's depth - linear distance instead
  16. //of the GPU's distance^2, since we want precision. Basically,
  17. //in addition to storing color information on a final output texture,
  18. //we store the distance from the camera to the rendered pixel.
  19. //
  20. //Pass 2 is the creation of the Ambient Occlusion texture. We
  21. //load a texture created by a random noise function and take samples
  22. //from around the pixel to reduce banding. The output is a single
  23. //float, which describes how occluded the pixel is by its surroundings:
  24. //0.0 for "completely blocked by surrounding pixels,"
  25. //1.0 for "not occluded at all." The result is a grainy black and
  26. //white texture.
  27. //
  28. //Pass 3 is the final post-process where we multiply the diffuse
  29. //color from pass 1 with the occlusion value we get by averaging
  30. //the surrounding pixels of pass 2. (We could sample from pass 2's
  31. //texture directly, but that results in a very grainy look.)
  32.  
  33. //////////////////////////////////////////////////////////////////////
  34. //
  35. //Model.cpp (or other objects' draw functions)
  36. //
  37. //Pass 1: Diffuse and Depth
  38.  
  39. void Model::Draw()
  40. {
  41.     //Hypothetical example - in reality, we'd batch draw calls
  42.     //by shader to change GPU state as little as possible.
  43.  
  44.     BindBuffers( m_VBO, m_IBO );
  45.     DrawIndicesWithTechnique( m_numVerts, m_numIndices,
  46.         Shader* m_diffuse, 0, 0 );
  47.     DrawIndicesWithTechnique( m_numVerts, m_numIndices,
  48.         Shader* m_depth, 0, 0 );
  49. }
  50.  
  51. //////////////////////////////////////////////////////////////////////
  52. //
  53. //Renderer.cpp
  54. //
  55. //Passes 2 and 3: Ambient Occlusion and Post-Processing
  56.  
  57.  
  58. void Renderer::Present(vec4 clearColor)
  59. {
  60.     BindBuffers(m_fullscreenVBO, m_fullscreenIBO);
  61.  
  62.     //Pass 2: Ambient Occlusion
  63.     SetRenderTarget(m_AmbientOcclusionTexture);
  64.  
  65.    
  66.     //SI_TEXTURE_1 is diffuse from pass 1
  67.     //SI_TEXTURE_2 is depth from pass 1
  68.     ApplyTexture(SI_TEXTURE_3, m_randomNoiseTexture);
  69.    
  70.     DrawIndicesWithTechnique( 4, 6, m_AmbientOcclusionTechnique,
  71.         0, 0 );
  72.  
  73.     //Pass 3: Final post-process and output
  74.     SetRenderTarget(m_PostProcessTexture);
  75.  
  76.     ApplyTexture(SI_TEXTURE_6, m_AmbientOcclusionTexture);
  77.  
  78.     DrawIndicesWithTechnique( 4, 6, m_PostProcessTechnique,
  79.         0, 0 );
  80.  
  81.  
  82.     HRESULT errcheck = m_swapchain->Present(0, 0);
  83.     CheckError(errcheck);
  84.  
  85.     ClearDepthBuffer();
  86. }
  87.  
  88. //////////////////////////////////////////////////////////////////////
  89. //
  90. //shader.fx - HLSL version of code
  91. //
  92.  
  93. ///////////////////////
  94. //Pass 1: Depth (and Diffuse, which isn't shown)
  95.  
  96. struct VtoDepth
  97. {
  98.     float4 pos:SV_POSITION;
  99.     float4 worldpos:WORLDPOS;
  100. };
  101.  
  102. void Depth_VS(
  103.     float4 pos:POSITION,
  104.     float4 tc:TEXCOORDS,
  105.     out VtoDepth vtd)
  106. {
  107.     vtd.pos = mul(pos, in_mvp);
  108.     vtd.worldpos = pos;
  109. }
  110.  
  111. float4 Depth_PS(VtoDepth vtd):SV_Target
  112. {
  113.     return float4(length(in_camerapos.xyz - vtd.worldpos.xyz));
  114. }
  115.  
  116. technique11 Depth
  117. {
  118.     pass P0
  119.     {
  120.         SetVertexShader(CompileShader(vs_4_0, Depth_VS()));
  121.         SetGeometryShader(NULL);
  122.         SetPixelShader(CompileShader(ps_4_0, Depth_PS()));
  123.     }
  124. }
  125.  
  126. ///////////////////////
  127. //Pass 2: Ambient Occlusion
  128.  
  129. struct VtoAmbientOcclusion
  130. {
  131.     float4 pos:SV_POSITION;
  132.     float4 tc:TEXCOORD;
  133. };
  134.  
  135. void AmbientOcclusion_VS(
  136.     float4 pos:POSITION,
  137.     float4 normal:NORMAL,
  138.     float4 tangent:TANGENT,
  139.     float4 tc:TEXCOORD,
  140.     out VtoAmbientOcclusion vtao)
  141. {
  142.     vtao.pos = pos;
  143.     vtao.tc = tc;
  144. }
  145.  
  146. //rotating kernel - we combine this with random noise
  147. //to get a randomly distributed set of points around each pixel
  148. //to reduce banding
  149.  
  150. static const float2 AO_SAMPLES[8] =
  151. {
  152.    float2(-0.71, 0.71), float2(0, 1),
  153.    float2(0.71, 0.71),  float2(0, -1),
  154.    float2(1, 0),        float2(0.71, -0.71),
  155.    float2(-1, 0),       float2(-0.71, -0.71)
  156. };
  157.  
  158. float4 AmbientOcclusion_PS(VtoAmbientOcclusion vtao):SV_Target
  159. {
  160.  
  161.     //currently bound to in_texture2: Random Noise
  162.     //currently bound to in_texture3: Scene Depth
  163.  
  164.     float3 rand = normalize
  165.         (in_texture2.Sample(ao, vtao.tc.xy).xyz) * 2.0 - 1.0;
  166.  
  167.     float thisPixelDepth = in_texture3.Sample(ao, vtao.tc.xy).w;
  168.  
  169.     float sum = 0.0;
  170.    
  171.     for(int i = 0; i < 8; ++i)      //8 rings
  172.     {
  173.         for(int k = 0; k < 8; ++k)  //8 points on that ring
  174.         {
  175.             float2 sampleUVs = vtao.tc.xy + (k / 8.0) *                     (AO_SAMPLES[k] + rand.xy) *
  176.                 float2( 1.0 / in_screenWidth,
  177.                 1.0 / in_screenHeight );
  178.  
  179.             float samplePixelDepth =
  180.                 in_texture3.Sample(ao, sampleUVs).x;
  181.  
  182.             float delta =
  183.                 thisPixelDepth - samplePixelDepth;
  184.  
  185.             if( delta > 1.0 && delta < 10.0)
  186.             {
  187.                 sum += 1.0;
  188.             }
  189.         }
  190.     }
  191.  
  192.     //get % of surrounding pixels that occlude this one
  193.     float occ = 1.0 - (sum / 64.0);
  194.    
  195.     return float4(occ, occ, occ, 1.0);
  196. }
  197.  
  198. technique11 AmbientOcclusion
  199. {
  200.     pass P0
  201.     {
  202.         SetVertexShader(CompileShader(vs_4_0,                       AmbientOcclusion_VS()));
  203.         SetGeometryShader(NULL);
  204.         SetPixelShader(CompileShader(ps_4_0,                        AmbientOcclusion_PS()));
  205.     }
  206. }
  207.  
  208. ///////////////////////
  209. //Pass 3: Final post-process and render
  210.  
  211. struct VtoPostprocess
  212. {
  213.     float4 pos:SV_POSITION;
  214.     float4 tc:TEXCOORD;
  215. };
  216.  
  217. void postprocessVS(
  218.     float4 pos:POSITION,
  219.     float4 tc:TEXCOORD,
  220.     out VtoPostprocess vtpp)
  221. {
  222.     vtpp.pos = pos;
  223.     vtpp.tc = tc;
  224. }
  225.  
  226. //lower = grainer, higher = smokier/smoother
  227. static const int SSAO_BLUR_AMOUNT = 8;
  228.  
  229. float4 postprocessPS(VtoPostprocess vtpp):SV_Target
  230. {
  231.     //currently bound to in_texture1: Diffuse map from pass 1
  232.     //currently bound to in_texture6: Ambient Occlusion pass 2
  233.  
  234.     float4 sceneColor = in_texture1.Sample(defss, vtpp.tc.xy);
  235.        
  236.     sceneColor = toneMap(sceneColor, in_texture6.Sample(defss,      float2(0.5, 0.5)));
  237.  
  238.     //get occlusion and blur from surrounding pixels
  239.     //so that end result isn't grainy
  240.  
  241.     float occ = 0.0;
  242.     for(int x = 0; x < SSAO_BLUR_AMOUNT; ++x)
  243.     {
  244.         for(int y = 0; y < SSAO_BLUR_AMOUNT; ++y)
  245.         {
  246.             occ += in_texture8.Sample(defss, vtpp.tc.xy,                int2(x - SSAO_BLUR_AMOUNT * 0.5,
  247.             y - SSAO_BLUR_AMOUNT * 0.5)).x;
  248.         }
  249.     }
  250.     occ /= (SSAO_BLUR_AMOUNT * SSAO_BLUR_AMOUNT);
  251.    
  252.     return sceneColor * occ;
  253. }
  254.  
  255. technique11 postprocess
  256. {
  257.     pass P0
  258.     {
  259.         SetVertexShader(CompileShader(vs_4_0,
  260.             postprocessVS()));
  261.         SetGeometryShader(NULL);
  262.         SetPixelShader(CompileShader(ps_4_0, postprocessPS()));
  263.     }
  264. }
RAW Paste Data