1. Steve Streeting
  2. ogre

Commits

David Rogers  committed 9aef9e8

New sample from Simon Wallner demonstrating various techniques for implementing SSAO using Ogre's compositors.

  • Participants
  • Parent commits b164161
  • Branches v1-8

Comments (0)

Files changed (43)

File CMake/Templates/resources.cfg.in

View file
 FileSystem=@OGRE_MEDIA_DIR_REL@/PCZAppMedia
 FileSystem=@OGRE_MEDIA_DIR_REL@/RTShaderLib
 FileSystem=@OGRE_MEDIA_DIR_REL@/RTShaderLib/materials
+FileSystem=@OGRE_MEDIA_DIR_REL@/materials/scripts/SSAO
+FileSystem=@OGRE_MEDIA_DIR_REL@/materials/textures/SSAO
 Zip=@OGRE_MEDIA_DIR_REL@/packs/cubemap.zip
 Zip=@OGRE_MEDIA_DIR_REL@/packs/cubemapsJS.zip
 Zip=@OGRE_MEDIA_DIR_REL@/packs/dragon.zip

File CMake/Templates/resources_d.cfg.in

View file
 FileSystem=@OGRE_MEDIA_DIR_DBG@/PCZAppMedia
 FileSystem=@OGRE_MEDIA_DIR_DBG@/RTShaderLib
 FileSystem=@OGRE_MEDIA_DIR_DBG@/RTShaderLib/materials
+FileSystem=@OGRE_MEDIA_DIR_DBG@/materials/scripts/SSAO
+FileSystem=@OGRE_MEDIA_DIR_DBG@/materials/textures/SSAO
 Zip=@OGRE_MEDIA_DIR_DBG@/packs/cubemap.zip
 Zip=@OGRE_MEDIA_DIR_DBG@/packs/cubemapsJS.zip
 Zip=@OGRE_MEDIA_DIR_DBG@/packs/dragon.zip

File CMake/Templates/samples.cfg.in

View file
 SamplePlugin=Sample_SkyPlane
 SamplePlugin=Sample_Smoke
 SamplePlugin=Sample_SphereMapping
+SamplePlugin=Sample_SSAO
 SamplePlugin=Sample_Terrain
 SamplePlugin=Sample_TextureArray
 SamplePlugin=Sample_TextureFX

File CMake/Templates/samples_d.cfg.in

View file
 SamplePlugin=Sample_SkyPlane_d
 SamplePlugin=Sample_Smoke_d
 SamplePlugin=Sample_SphereMapping_d
+SamplePlugin=Sample_SSAO_d
 SamplePlugin=Sample_Terrain_d
 SamplePlugin=Sample_TextureFX_d
 SamplePlugin=Sample_TextureArray_d

File Samples/Browser/include/SampleBrowser.h

View file
 #include "OceanDemo.h"
 #include "Terrain.h"
 #include "Water.h"
-//#endif
 #include "BezierPatch.h"
 #include "CameraTrack.h"
 #include "CharacterSample.h"
 #include "SkyPlane.h"
 #include "Smoke.h"
 #include "SphereMapping.h"
+#include "SSAO.h"
 #include "TextureFX.h"
 #include "TextureArray.h"
 #include "Transparency.h"
 				mPluginNameMap["Sample_Ocean"]              = (OgreBites::SdkSample *) OGRE_NEW Sample_Ocean();
 				mPluginNameMap["Sample_Water"]              = (OgreBites::SdkSample *) OGRE_NEW Sample_Water();
 				mPluginNameMap["Sample_ShaderSystem"]       = (OgreBites::SdkSample *) OGRE_NEW Sample_ShaderSystem();
+				mPluginNameMap["Sample_SSAO"]               = (OgreBites::SdkSample *) OGRE_NEW Sample_SSAO();
                 mPluginNameMap["Sample_Terrain"]            = (OgreBites::SdkSample *) OGRE_NEW Sample_Terrain();
             }
 #endif

File Samples/CMakeLists.txt

View file
   add_subdirectory(Fresnel)
   add_subdirectory(Isosurf)
   add_subdirectory(ParticleGS)
+  add_subdirectory(SSAO)
 endif ()
 
   # Add browser last

File Samples/Media/materials/scripts/SSAO/ClearGBuffer.cg

View file
+void ClearGBuffer_fp
+(
+    out float4 oColor0 : COLOR0,
+    out float4 oColor1 : COLOR1,
+    out float4 oColor2 : COLOR2
+)
+{
+    oColor0 = float4(0, 0, 0, 0);    // rgba
+    oColor1 = float4(0.5, 0.5, 0.5, 1);    // normal + liear depth [0..1]
+    oColor2 = float4(0, 0, 0, 0);    // position in view space + unused
+}

File Samples/Media/materials/scripts/SSAO/ClearGBuffer.material

View file
+fragment_program SSAO/ClearGBuffer_fp cg
+{
+    source ClearGBuffer.cg
+    entry_point ClearGBuffer_fp
+    profiles ps_2_x arbfp1
+}
+
+material SSAO/ClearGBuffer
+{
+    technique
+    {
+        pass
+        {
+            depth_write off
+
+            fragment_program_ref SSAO/ClearGBuffer_fp {}
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/CreaseShading.cg

View file
+// original sources found at Game Developer Magazine March 2008
+
+void CreaseShading_fp
+(
+    in float2 uv : TEXCOORD0,
+
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sNormal : register(s0),    // xyz normal + depth [0, 1]
+    uniform sampler sPosition : register(s1),  // view space position
+    uniform sampler sRandom : register(s2),    // random texture sampler
+    uniform const float cRange, // the three(four) artistic parameters
+    uniform const float cBias,
+    uniform const float cAverager,
+    uniform const float cMinimumCrease,
+    uniform const float cKernelSize, // Bias for the kernel size, Hack for the fixed size 11x11 stipple kernel
+    uniform const float4 cViewportSize // (width, height, 1/width, 1/height)
+)
+{
+    // get the view space position and normal of the fragment
+    const float3 fragmentPosition = tex2D(sPosition, uv).xyz;
+    const float3 fragmentNormal = tex2D(sNormal, uv).xyz;
+
+    float totalGI = 0.0f;
+    
+    // a diamond shaped (45deg rotated square) stipple pattern around (0, 0) this will be used as offset for the samples
+    //        O
+    //       O O
+    //      O O O
+    //     O O O O
+    //    O O X O O
+    //     O O O O
+    //      O O O
+    //       O O
+    //        O
+    // the algorith starts with the leftmost element and walks the diagonal to the topmost element
+    // a stippleSize of n yields (((n - 1) / 2)^2) - 1 samples
+    // the 'image' above has a stipple size of 11 'cuz it has 5 samples (minus
+    // the current fragment position and 4 gaps = 11.
+
+    const int stippleSize = 11; // must be odd
+    for (int i = 0; i < (stippleSize + 1) / 2; i++)
+    {
+        float2 diagonalStart = float2(-(stippleSize - 1) / 2, 0) + i;
+        for(int j = 0; j < (stippleSize + 1) / 2; j++)
+        {
+            float2 sampleOffset = diagonalStart + float2(j, -j);
+
+            float2 sampleUV = uv + (sampleOffset * cViewportSize.zw * cKernelSize);
+            float3 samplePos = tex2D(sPosition, sampleUV).xyz;
+
+            float3 toCenter = samplePos - fragmentPosition;
+            float distance = length(toCenter);
+
+            toCenter = normalize(toCenter);
+            float centerContrib = saturate((dot(toCenter, fragmentNormal) - cMinimumCrease) * cBias);
+            float rangeAttenuation = 1.0f - saturate(distance / cRange);
+
+            totalGI += centerContrib * rangeAttenuation;
+        }
+    }
+    
+    totalGI /= cAverager;
+    oColor0 = 1 - float4(totalGI.xxx, 1);
+}

File Samples/Media/materials/scripts/SSAO/CreaseShading.material

View file
+fragment_program SSAO/CreaseShading_fp cg
+{
+    source CreaseShading.cg
+    entry_point CreaseShading_fp
+    profiles ps_2_x arbfp1
+}
+
+material SSAO/CreaseShading
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/CreaseShading_fp
+            {
+                param_named_auto cViewportSize viewport_size
+            }
+
+            texture_unit // normals
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit // view space position
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit // random texture will be replace by 11x11 stipple
+            {
+                texture rand1x32.png
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/Crytek.cg

View file
+void Crytek_fp
+(
+    in float2 fragmentTC : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sSceneDepthSampler : register(s0), // depth = w component [0, 1]
+    uniform sampler sRotSampler4x4 : register(s1),  // rotation sampler -> pseudo random spherical weighted sampling
+    uniform float4 cViewportSize, // auto param width/height/inv. width/inv. height
+    uniform float cFov, // vertical field of view in radians
+    uniform float farClipDistance,
+    uniform float nearClipDistance,
+    uniform float cSampleInScreenspace, // whether to sample in screen or world space
+    uniform float cSampleLengthScreenSpace, // The sample length in screen space [0, 1]
+    uniform float cSampleLengthWorldSpace, // the sample length in world space in units
+    uniform float cOffsetScale, // [0, 1] The distance of the first sample. samples are the 
+        // placed in [cOffsetScale * cSampleLengthScreenSpace, cSampleLengthScreenSpace]
+    uniform float cDefaultAccessibility, // the default value used in the lerp() expression for invalid samples [0, 1]
+    uniform float cEdgeHighlight // multiplier for edge highlighting in [1, 2] 1 is full highlighting 2 is off
+)
+{
+    const int nSampleNum = 32; // number of samples
+
+    // compute the distance between the clipping planes to convert [0, 1] depth to world space units
+    const float clipDepth = farClipDistance - nearClipDistance;
+
+    // get the depth of the current pixel and convert into world space unit [0, inf]
+    float fragmentWorldDepth = tex2D(sSceneDepthSampler, fragmentTC).w * clipDepth;
+
+    // get rotation vector, rotation is tiled every 4 screen pixels
+    float2 rotationTC = fragmentTC * cViewportSize.xy / 4;
+    float3 rotationVector = 2 * tex2D(sRotSampler4x4, rotationTC).xyz - 1; // [-1, 1]x[-1. 1]x[-1. 1]
+    
+    float rUV = 0; // radius of influence in screen space
+    float r = 0; // radius of influence in world space
+    if (cSampleInScreenspace == 1)
+    {
+        rUV = cSampleLengthScreenSpace;
+        r = tan(rUV * cFov) * fragmentWorldDepth;
+    }
+    else
+    {
+        rUV = atan(cSampleLengthWorldSpace / fragmentWorldDepth) / cFov; // the radius of influence projected into screen space
+        r = cSampleLengthWorldSpace;
+    }
+
+    float sampleLength = cOffsetScale; // the offset for the first sample
+    const float sampleLengthStep = pow((rUV / sampleLength), 1.0f/nSampleNum);
+    
+    float accessibility = 0;
+    // sample the sphere and accumulate accessibility
+    for (int i = 0; i < (nSampleNum/8); i++)
+    {
+        for (int x = -1; x <= 1; x += 2)
+        for (int y = -1; y <= 1; y += 2)
+        for (int z = -1; z <= 1; z += 2)
+        {
+            //generate offset vector
+            float3 offset = normalize(float3(x, y, z)) * sampleLength;
+            
+            // update sample length
+            sampleLength *= sampleLengthStep;
+        
+            // reflect offset vector by random rotation sample (i.e. rotating it) 
+            float3 rotatedOffset = reflect(offset, rotationVector);
+                    
+            float2 sampleTC = fragmentTC + rotatedOffset.xy * rUV;
+                
+            // read scene depth at sampling point and convert into world space units (m or whatever)
+            float sampleWorldDepth = tex2D(sSceneDepthSampler, sampleTC).w * clipDepth;
+            
+            // check if depths of both pixels are close enough and sampling point should affect our center pixel
+            float fRangeIsInvalid = saturate((fragmentWorldDepth - sampleWorldDepth) / r);
+            
+            // accumulate accessibility, use default value of 0.5 if right computations are not possible
+            accessibility += lerp(sampleWorldDepth > (fragmentWorldDepth + rotatedOffset.z * r), cDefaultAccessibility, fRangeIsInvalid);
+        }
+    }
+    
+    // get average value
+    accessibility /= nSampleNum;
+
+    // normalize, remove edge highlighting
+    accessibility *= cEdgeHighlight;
+    
+    // amplify and saturate if necessary
+    oColor0 = float4(accessibility.xxx, 1);
+}

File Samples/Media/materials/scripts/SSAO/Crytek.material

View file
+fragment_program SSAO/Crytek_fp cg
+{
+    source Crytek.cg
+    entry_point Crytek_fp
+    profiles ps_3_0 arbfp1
+}
+
+material SSAO/Crytek
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+            
+            fragment_program_ref SSAO/Crytek_fp
+            {
+                param_named_auto cViewportSize viewport_size
+                param_named_auto farClipDistance far_clip_distance
+                param_named_auto nearClipDistance near_clip_distance
+                param_named_auto cFov fov
+            }
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+            
+            texture_unit
+            {
+                // texture regularSphere4.png
+                texture regularSphereJittered4.png
+                // texture regularSphereOctant4.png
+                // texture regularSphereJitteredOctant4.png
+                // texture rand4x4.png
+                tex_address_mode wrap
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/GBuffer.cg

View file
+// courtesy of the ogre wiki and the defered shading sample
+// http://www.ogre3d.org/wiki/index.php/Deferred_Shading
+//------------------------------------------------------------------------------
+
+void GBuffer_vp(
+        float4 iPosition : POSITION,
+        float3 iNormal   : NORMAL,
+        float2 iUV0 : TEXCOORD0,
+
+        out float4 oPosition : POSITION,
+        out float3 oViewPos : TEXCOORD0,
+        out float3 oNormal : TEXCOORD1,
+
+        uniform float4x4 cWorldViewProj,
+        uniform float4x4 cWorldView
+        )
+{
+        oPosition = mul(cWorldViewProj, iPosition);         // transform the vertex position to the projection space
+        oViewPos = mul(cWorldView, iPosition).xyz;          // transform the vertex position to the view space
+        oNormal = mul(cWorldView, float4(iNormal,0)).xyz;   // transform the vertex normal to view space
+}
+
+void GBuffer_fp(
+        float3 iViewPos : TEXCOORD0,
+        float3 iNormal  : TEXCOORD1,
+
+        out float4 oColor0 : COLOR0,        // rgb color
+        out float4 oNormalDepth : COLOR1,   // normal + linear depth [0, 1]
+        out float4 oViewPos : COLOR2,       // view space position
+        
+        uniform float cNearClipDistance,
+        uniform float cFarClipDistance // !!! might be 0 for infinite view projection.
+        )
+{
+        oColor0.rgb = 1; //...and a least little touch of the titanium white...
+        oColor0.a = 0; // not used
+        
+        oNormalDepth.xyz = normalize(iNormal);
+        
+        float clipDistance = cFarClipDistance - cNearClipDistance;
+        oNormalDepth.w = (length(iViewPos.z) - cNearClipDistance) / clipDistance; // norm to [0, 1]
+        oViewPos.xyz = float4(iViewPos, 0);
+}
+

File Samples/Media/materials/scripts/SSAO/GBuffer.material

View file
+// Gbuffer Material
+
+vertex_program SSAO/GBuffer_vp cg
+{
+    source GBuffer.cg
+    entry_point GBuffer_vp
+    profiles vs_2_x arbvp1
+}
+
+fragment_program SSAO/GBuffer_fp cg
+{
+    source GBuffer.cg
+    entry_point GBuffer_fp
+    profiles ps_3_0 arbfp1
+}
+
+material SSAO/GBuffer
+{
+    technique
+    {
+        pass
+        {
+            vertex_program_ref SSAO/GBuffer_vp
+            {
+                param_named_auto cWorldViewProj worldviewproj_matrix
+                param_named_auto cWorldView worldview_matrix
+            }
+
+            fragment_program_ref SSAO/GBuffer_fp
+            {
+                param_named_auto cNearClipDistance near_clip_distance
+                param_named_auto cFarClipDistance far_clip_distance
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/HemisphereMC.cg

View file
+void HemisphereMC_fp
+(
+    in const float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sMRT1 : register(s0), // fragment normals
+    uniform sampler sMRT2 : register(s1), // view space position, remember that we are looking down the negative Z axis!!!
+    uniform sampler sRand : register(s2), // MxN random texture, M sets of N precomputed low-discrepancy samples
+    
+    uniform const float4 cViewportSize, // (viewport_width, viewport_height, inverse_viewport_width, inverse_viewport_height)
+    uniform const float cFov, // vertical field of view in radians
+    uniform const float cSampleInScreenspace, // whether to sample in screen or world space
+    uniform const float cSampleLengthScreenSpace, // The sample length in screen space [0, 1]
+    uniform const float cSampleLengthWorldSpace, // the sample length in world space in units
+    uniform const float cSampleLengthExponent // The exponent of the sample length
+)
+{
+    const int interleaved = 4;
+    const int m = 8;
+    const int n = 4;
+    const int numSamples = m * n;
+    const float2 interleaveOffset = uv * cViewportSize.xy / interleaved;
+    const float3 fragmentPosition = tex2D(sMRT2, uv).xyz; // the current fragment in view space
+    const float3 fragmentNormal = tex2D(sMRT1, uv).xyz; // the fragment normal
+    float rUV = 0; // radius of influence in screen space
+    float r = 0; // radius of influence in world space
+
+    if (cSampleInScreenspace == 1)
+    {
+        rUV = cSampleLengthScreenSpace;
+        r = tan(rUV * cFov) * -fragmentPosition.z;
+    }
+    else
+    {
+        rUV = atan(cSampleLengthWorldSpace / -fragmentPosition.z) / cFov; // the radius of influence projected into screen space
+        r = cSampleLengthWorldSpace;
+    }
+
+    if (rUV < (cViewportSize.z)) // abort if the projected radius of influence is smaller than 1 fragment
+    {
+        oColor0 = 1;
+        return;
+    }
+    
+
+    float accessibility = 0; // accessibility of the fragment
+
+    const float3 viewVector = float3(0, 0, 1); // the constant view vector in view space
+
+    // the reflection vector to align the hemisphere with the fragment normal
+    // somehow the x component must be flipped...???
+    const float3 reflector = normalize(fragmentNormal + viewVector) * float3(-1, 1, 1); 
+
+    float count = 0;
+    float sampleLength;
+
+    for (float i = 0.0f; i < m; i++)
+    for (float j = 0.0f; j < n; j++)
+    {
+        count ++;
+
+        const float2 randomTC = interleaveOffset + float2(i/(interleaved * m), j/(interleaved * n)); 
+        float3 randomVector = (tex2D(sRand, randomTC) * 2 - 1); // unpack to [-1, 1]x[-1, 1]x[1, 1]
+
+        sampleLength = pow(count/(float)numSamples, cSampleLengthExponent);
+
+        const float3 sampleVector = reflect(randomVector, reflector) * sampleLength;
+
+        const float2 sampleTC = uv + sampleVector.xy * rUV;
+
+        const float3 samplePosition = tex2D(sMRT2, sampleTC);
+
+        if (samplePosition.z < (fragmentPosition.z - sampleVector.z * r)) // thin air
+            accessibility++;
+        else // solid geometry
+            accessibility += length(fragmentPosition - samplePosition) > r; // out of reach, i.e. false occluder
+    }
+
+    accessibility /= numSamples;
+    oColor0 = float4(accessibility.xxx, 1);
+
+    float3 direction = 0;
+    direction += reflect(float3(0, 0, -1), reflector);
+    direction = normalize(direction);
+}

File Samples/Media/materials/scripts/SSAO/HemisphereMC.material

View file
+fragment_program SSAO/HemisphereMC_fp cg
+{
+    source HemisphereMC.cg
+    entry_point HemisphereMC_fp
+    profiles ps_3_0 arbfp1
+}
+
+// Monte Carlo Integration of the hemisphere definded by the fragment normal
+// lossely based on Ritschel et al. SSDO.
+material SSAO/HemisphereMC
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/HemisphereMC_fp
+            {
+                param_named_auto cViewportSize viewport_size
+                param_named_auto cFov fov
+            }
+
+            texture_unit // normals
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit // view space position
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit
+            {
+                texture importance4InterleavedSphereHemisphere8x4.png
+                tex_address_mode wrap
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/HorizonBased.cg

View file
+void HorizonBased_fp
+(
+    in float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sMRT1 : register(s0), // fragment normal
+    uniform sampler sMRT2 : register(s1), // view space position
+    uniform sampler sRand : register(s2),  // (cos(a), sin(a), jitter
+    
+    uniform float4 cViewportSize, // (viewport_width, viewport_height, inverse_viewport_width, inverse_viewport_height)
+    uniform float cFov, // vertical field of view in radians
+    uniform float cSampleInScreenspace, // whether to sample in screen or world space
+    uniform float cSampleLengthScreenSpace, // The sample length in screen space [0, 1]
+    uniform float cSampleLengthWorldSpace, // the sample length in world space in units
+    uniform float cAngleBias // angle bias to avoid shadows in low tessellated curvatures [0, pi/2]
+)
+{
+    const float pi = 3.1415926535897932384626433832795028841971693993751;
+
+    const float numSteps = 7; // number of samples/steps along a direction
+    const float numDirections = 4; // number of sampling directions in uv space
+    
+    float3 point = tex2D(sMRT2, uv).xyz; // the current fragment in view space
+    float3 pointNormal = tex2D(sMRT1, uv).xyz; // the fragment normal
+
+    float Ruv = 0; // radius of influence in screen space
+    float R = 0; // radius of influence in world space
+    if (cSampleInScreenspace == 1)
+    {
+        Ruv = cSampleLengthScreenSpace;
+        R = tan(Ruv * cFov) * -point.z;
+    }
+    else
+    {
+        Ruv = atan(cSampleLengthWorldSpace / -point.z) / cFov; // the radius of influence projected into screen space
+        R = cSampleLengthWorldSpace;
+    }
+
+    // if the radius of influence is smaller than one fragment we exit early,
+    // since all samples would hit the current fragment.
+    if (Ruv < (1 / cViewportSize.x))
+    {
+        oColor0 = float4(1, 1, 1, 1);
+        return;
+    }
+
+    float occlusion = 0; // occlusion of the fragment
+    float2x2 directionMatrix;    // the matrix to create the sample directions
+                                 // the compiler should evaluate the directions at compile time
+    directionMatrix._m00 = cos((2 * pi) / numDirections);
+    directionMatrix._m01 = sin((2 * pi) / numDirections);
+    directionMatrix._m10 = - sin((2 * pi) / numDirections);
+    directionMatrix._m11 = cos((2 * pi) / numDirections);
+    float2 deltaUV = float2(1, 0) * (Ruv / (numSteps + 1)); // The step vector in view space. scale it to the step size
+            // we don't want to sample to the perimeter of R since those samples would be 
+            // omitted by the distance attenuation (W(R) = 0 by definition)
+            // Therefore we add a extra step and don't use the last sample.
+
+    float3 randomValues = tex2D(sRand, (uv * cViewportSize.xy) / 4); //4px tiles
+    float2x2 rotationMatrix;
+    rotationMatrix._m00 = (randomValues.x - 0.5) * 2;
+    rotationMatrix._m01 = (randomValues.y - 0.5) * 2;
+    rotationMatrix._m10 = - rotationMatrix._m01;
+    rotationMatrix._m11 = rotationMatrix._m00;
+    float jitter = randomValues.z;
+
+    for (int i = 0; i < numDirections; i++)
+    {
+        deltaUV = mul(deltaUV, directionMatrix); // rotate the deltaUV vector by 1/numDirections
+        float2 sampleDirection = mul(deltaUV, rotationMatrix); // now rotate this vector with the random rotation
+
+        float oldAngle = cAngleBias;
+
+        for (int j = 1; j <= numSteps; j++) // sample along a direction, needs to start at one, for the sake of the next line
+        {
+            float2 sampleUV = uv + ((jitter + j) * sampleDirection); // jitter the step a little bit
+            
+            float3 sample = tex2D(sMRT2, sampleUV); // the sample in view space
+            float3 sampleVector = (sample - point);
+            float gamma = (pi / 2) - acos(dot(pointNormal, normalize(sampleVector))); //the angle between the fragment tangent and the sample
+
+            if (gamma > oldAngle) 
+            {
+                float attenuation = saturate(1 - (pow((length(sampleVector) / R), 2)));
+                occlusion += attenuation * (sin(gamma) - sin(oldAngle));
+                oldAngle = gamma;
+            }
+        }
+    }
+
+    // ??? should step samples that fall under the horizontal be considered in the following line??? 
+    occlusion /= (numDirections * numSteps);
+    oColor0 = 1 - float4(occlusion.xxx, 1) * 2 * pi;
+}

File Samples/Media/materials/scripts/SSAO/HorizonBased.material

View file
+fragment_program SSAO/HorizonBased_fp cg
+{
+    source HorizonBased.cg
+    entry_point HorizonBased_fp
+    profiles ps_3_0 arbfp1
+}
+
+material SSAO/HorizonBased
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/HorizonBased_fp
+            {
+                param_named_auto cViewportSize viewport_size
+                param_named_auto cFov fov
+            }
+
+            texture_unit // fragment normal
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit // view position
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit
+            {
+                texture randCosSinJitter4x4.png
+                tex_address_mode wrap
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/SSAO.compositor

View file
+compositor SSAO/GBuffer
+{
+    technique
+    {
+        // GBuffer enconding: --------------------------------------------------
+        // mrt0: rgba --> unused in this sample (plain white, (1, 1, 1, 1))
+        // mrt1: xyz --> normals, w --> normalized linear depth [0, 1]
+        // mrt2: xyz --> position in view space
+        // 
+        // use a better packing of variables in the mrt to (possibly) increase
+        // performance!
+        // ---------------------------------------------------------------------
+        
+        texture mrt target_width target_height PF_FLOAT32_RGBA PF_FLOAT32_RGBA PF_FLOAT32_RGBA chain_scope
+        texture occlusion target_width target_height PF_FLOAT32_RGBA chain_scope
+
+        target mrt
+        {
+            input none
+            shadows off
+            
+            pass clear {}
+            
+            pass render_quad
+            {
+                material SSAO/ClearGBuffer
+            }            
+
+            pass render_scene {}
+        }
+    }
+}
+
+compositor SSAO/Volumetric // Szirmay-Kalos et al 2010
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/Volumetric
+            }
+        }
+    }
+}
+
+
+compositor SSAO/HemisphereMC // Ritschel et al. inspired hemisphere mc integration
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/HemisphereMC
+            }
+        }
+    }
+}
+
+compositor SSAO/HorizonBased // Bavoil and Sainz in ShaderX7
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/HorizonBased
+            }
+        }
+    }
+}
+
+
+compositor SSAO/Crytek // Crytek style ssao as found in shaderX7
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/Crytek
+            }
+        }
+    }
+}
+
+
+compositor SSAO/CreaseShading // Megan Fox's crease shading http://www.shalinor.com/research.html
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/CreaseShading
+            }
+        }
+    }
+}
+
+compositor SSAO/UnsharpMask //Unsharp mask the depth buffer [LCD2006]
+{
+    technique
+    {
+        texture blurred target_width target_height PF_FLOAT32_RGBA
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target blurred
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/UnsharpMask/GaussianBlurX
+            }
+        }
+
+        target blurred
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/UnsharpMask/GaussianBlurY
+                input 0 blurred
+            }
+        }
+
+        target occlusion
+        {
+            input none
+            pass clear {}
+            
+            pass render_quad
+            {
+                material SSAO/UnsharpMask
+                input 0 blurred
+            }
+        }
+    }
+}
+
+compositor SSAO/ShowNormals
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                // Renders a fullscreen quad with a material
+                material SSAO/ShowNormals
+            }
+        }
+    }
+}
+
+compositor SSAO/ShowDepth
+{
+    technique 
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                // Renders a fullscreen quad with a material
+                material SSAO/ShowDepth
+            }
+        }
+    }
+}
+
+compositor SSAO/ShowViewPos
+{
+    technique
+    {
+        texture_ref occlusion SSAO/GBuffer occlusion
+
+        target occlusion
+        {
+            input none
+            
+            pass render_quad
+            {
+                // Renders a fullscreen quad with a material
+                material SSAO/ShowViewPos
+            }
+        }
+    }
+}
+

File Samples/Media/materials/scripts/SSAO/SSAOPost.cg

View file
+void noFilter_fp (
+    in float2 uv : TEXCOORD0,
+    out float4 oColor0 : COLOR0,
+
+    uniform sampler sOcclusion : register(s0)
+)
+{
+    oColor0 = float4(tex2D(sOcclusion, uv).xyz, 1);
+} 
+
+
+// a very simple 4x4 box filter
+// the kernel has the following form
+//   o o o o
+//   o o o o
+//   o o x o
+//   o o o o 
+// where x marks the fragment position and the o marks a sampling point
+void boxFilter_fp
+(
+    in float2 screenTC : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+
+    uniform sampler sOcclusion : register(s0),
+    uniform float4 screenSize,
+    uniform float farClipDistance
+)
+{
+    float color = 0;
+    for (int x = -2; x < 2; x++)
+    for (int y = -2; y < 2; y++)
+    {
+        color += tex2D(sOcclusion, float2(screenTC.x + x * screenSize.z, screenTC.y + y * screenSize.w)).x;
+    }
+    color /= 16;
+        
+    oColor0 = float4(color.xxx, 1);
+}
+
+
+// a very simple and slightly dumb depth aware 4x4 box filter
+// the kernel has the following form
+//   o o o o
+//   o o o o
+//   o o x o
+//   o o o o 
+// where x marks the fragment position and the o marks a sampling point
+void smartBoxFilter_fp
+(
+    in float2 screenTC : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+
+    uniform sampler sMrt1 : register(s0), // normals + depth
+    uniform sampler sOcclusion : register(s1),
+    uniform float4 screenSize,
+    uniform float farClipDistance
+)
+{
+    float fragmentDepth = tex2D(sMrt1, screenTC).x;
+
+    float color = 0;
+    float weight = 0;
+    for (int x = -2; x < 2; x++)
+    for (int y = -2; y < 2; y++)
+    {
+        float sampleDepth = tex2D(sMrt1, float2(screenTC.x + x * screenSize.z, screenTC.y + y * screenSize.w)).x;
+        float dist = abs(fragmentDepth - sampleDepth) * farClipDistance + 0.5;
+        float sampleWeight = 1 / (pow(dist, 1) + 1);
+        color += sampleWeight * tex2D(sOcclusion, float2(screenTC.x + x * screenSize.z, screenTC.y + y * screenSize.w)).x;
+        weight += sampleWeight;
+    }
+    color /= weight;
+        
+    oColor0 = float4(color.xxx, 1);
+//    oColor0 = float4(tex2D(sOcclusion, screenTC).www, 1);
+}
+
+
+// cross bilateral filter
+// gaussian blur with photometric weighting
+// note: encode the viewspace z component in the accessibility texture to reduce
+// the texture fetch count
+void crossBilateralFilterX_fp
+(
+    in float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sAccessibility : register(s0),
+    uniform sampler sMRT2 : register(s1), // the view space position, xyz
+    
+    uniform float stepX, // inverse viewport width
+    uniform float cPhotometricExponent
+)
+{
+    const int kernelWidth = 13;
+    float sigma = (kernelWidth - 1) / 6; // make the kernel span 6 sigma
+    
+    float fragmentDepth = tex2D(sMRT2, uv).z;
+
+    float weights = 0;
+    float blurred = 0;
+    
+    for (float i = -(kernelWidth - 1) / 2; i < (kernelWidth - 1) / 2; i++)
+    {
+        float geometricWeight = exp(-pow(i, 2) / (2 * pow(sigma, 2)));
+        float sampleDepth = tex2D(sMRT2, float2(uv.x - i * stepX, uv.y)).z;
+        float photometricWeight = 1 / pow((1 + abs(fragmentDepth - sampleDepth)), cPhotometricExponent);
+
+        weights += (geometricWeight * photometricWeight);
+        blurred += tex2D(sAccessibility, float2(uv.x - i * stepX, uv.y)).r * geometricWeight * photometricWeight;
+    }
+
+    blurred /= weights;
+    oColor0 = float4(blurred.xxx, 1);
+}
+
+void crossBilateralFilterY_fp
+(
+    in float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sAccessibility : register(s0),
+    uniform sampler sMRT2 : register(s1), // the view space position, xyz
+    
+    uniform float stepY, // inverse viewport width
+    uniform float cPhotometricExponent
+)
+{
+    const int kernelWidth = 13;
+    float sigma = (kernelWidth - 1) / 6; // make the kernel span 6 sigma
+    
+    float fragmentDepth = tex2D(sMRT2, uv).z;
+
+    float weights = 0;
+    float blurred = 0;
+    
+    for (float i = -(kernelWidth - 1) / 2; i < (kernelWidth - 1) / 2; i++)
+    {
+        float geometricWeight = exp(-pow(i, 2) / (2 * pow(sigma, 2)));
+        float sampleDepth = tex2D(sMRT2, float2(uv.x, uv.y - i * stepY)).z;
+        float photometricWeight = 1 / pow((1 + abs(fragmentDepth - sampleDepth)), cPhotometricExponent);
+        
+        weights += (geometricWeight * photometricWeight);
+        blurred += tex2D(sAccessibility, float2(uv.x, uv.y - i * stepY)).r * geometricWeight * photometricWeight;
+    }
+
+    blurred /= weights;
+    oColor0 = float4(blurred.xxx, 1);
+}

File Samples/Media/materials/scripts/SSAO/SSAOPost.compositor

View file
+compositor SSAO/Post/NoFilter
+{
+    technique 
+    {
+        target_output
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/Post/NoFilter
+            }
+        }
+    }
+}
+
+compositor SSAO/Post/BoxFilter
+{
+    technique 
+    {
+        target_output
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/Post/BoxFilter
+            }
+        }
+    }
+}
+
+compositor SSAO/Post/SmartBoxFilter
+{
+    technique 
+    {
+        target_output
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/Post/SmartBoxFilter
+            }
+        }
+    }
+}
+
+
+compositor SSAO/Post/CrossBilateralFilter
+{
+    technique
+    {
+        texture accessibility target_width target_height PF_R8G8B8A8
+
+        target accessibility
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/HorizonBased/CrossBilateralFilter/X
+            }
+        }
+
+        target_output
+        {
+            input none
+            
+            pass render_quad
+            {
+                material SSAO/HorizonBased/CrossBilateralFilter/Y
+                input 0 accessibility
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/SSAOPost.material

View file
+fragment_program SSAO/Post/NoFilter_fp cg
+{
+    source SSAOPost.cg
+    entry_point noFilter_fp
+    profiles ps_3_0 arbfp1
+}
+
+fragment_program SSAO/Post/BoxFilter_fp cg
+{
+    source SSAOPost.cg
+    entry_point boxFilter_fp
+    profiles ps_3_0 arbfp1
+}
+
+fragment_program SSAO/Post/SmartBoxFilter_fp cg
+{
+    source SSAOPost.cg
+    entry_point smartBoxFilter_fp
+    profiles ps_3_0 arbfp1
+}
+
+fragment_program SSAO/HorizonBased/CrossBilateralFilter/X_fp cg
+{
+    source SSAOPost.cg
+    entry_point crossBilateralFilterX_fp
+    profiles ps_3_0 arbfp1 
+}
+
+fragment_program SSAO/HorizonBased/CrossBilateralFilter/Y_fp cg
+{
+    source SSAOPost.cg
+    entry_point crossBilateralFilterY_fp
+    profiles ps_3_0 arbfp1 
+}
+
+material SSAO/Post/NoFilter
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+            fragment_program_ref SSAO/Post/NoFilter_fp {}
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer occlusion
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}
+
+material SSAO/Post/BoxFilter
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/Post/BoxFilter_fp
+            {
+                param_named_auto screenSize viewport_size
+            }
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer occlusion
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}
+
+material SSAO/Post/SmartBoxFilter
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/Post/SmartBoxFilter_fp
+            {
+                param_named_auto screenSize viewport_size
+                param_named_auto farClipDistance far_clip_distance
+            }
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer occlusion
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}
+
+material SSAO/HorizonBased/CrossBilateralFilter/X
+{
+    technique
+    {
+        pass // two pass in x and y direction
+        {
+            depth_check off
+            
+            fragment_program_ref SSAO/HorizonBased/CrossBilateralFilter/X_fp
+            {
+                param_named_auto stepX inverse_viewport_width
+            }
+            
+            texture_unit // the accessability texture
+            {
+                content_type compositor SSAO/GBuffer occlusion
+                tex_address_mode clamp
+                filtering none
+            }
+            
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}
+
+material SSAO/HorizonBased/CrossBilateralFilter/Y
+{
+    technique
+    {
+        pass // two pass in x and y direction
+        {
+            depth_check off
+            
+            fragment_program_ref SSAO/HorizonBased/CrossBilateralFilter/Y_fp
+            {
+                param_named_auto stepY inverse_viewport_height
+            }
+            
+            texture_unit // the accessability texture, injected by the compositor
+            {
+                tex_address_mode clamp
+                filtering none
+            }
+            
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/ShowDepth.cg

View file
+void ShowDepth_fp
+(
+    in float2 iTexCoord: TEXCOORD0, 
+    
+    out float4 oColor0 : COLOR0,
+
+    uniform sampler mrt1: register(s0),
+    uniform sampler tex : register(s1)
+)
+{
+    float depth = tex2D(mrt1, iTexCoord).w;
+    oColor0 = float4(tex2D(tex, float2(depth*20, 0)).rgb, 1);
+}

File Samples/Media/materials/scripts/SSAO/ShowDepth.material

View file
+fragment_program SSAO/ShowDepth_fp cg
+{
+    source ShowDepth.cg
+    entry_point ShowDepth_fp
+    profiles ps_2_x arbfp1
+}
+
+material SSAO/ShowDepth
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/ShowDepth_fp {}
+
+            texture_unit 
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit
+            {
+                texture gray256.png
+                tex_address_mode wrap
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/ShowNormals.cg

View file
+void ShowNormals_fp
+(
+    in float2 iTexCoord : TEXCOORD0,
+    
+    out float4 oColor0: COLOR0,
+    
+    uniform sampler mrt1: register(s0)
+)
+{
+    oColor0 = float4(tex2D(mrt1, iTexCoord).xyz / 2 + 0.5, 1);
+}

File Samples/Media/materials/scripts/SSAO/ShowNormals.material

View file
+fragment_program SSAO/ShowNormals_fp cg
+{
+    source ShowNormals.cg
+    entry_point ShowNormals_fp
+    profiles ps_2_0 arbfp1
+}
+
+material SSAO/ShowNormals
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/ShowNormals_fp {}
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/ShowViewPos.cg

View file
+void ShowViewPos_fp
+(
+    in float2 iTexCoord : TEXCOORD0,
+    
+    out float4 oColor0: COLOR0,
+    
+    uniform sampler mrt2: register(s0)
+)
+{
+    oColor0 = float4(tex2D(mrt2, iTexCoord).xyz * float3(0.1, 0.1, -0.01), 1);
+}

File Samples/Media/materials/scripts/SSAO/ShowViewPos.material

View file
+fragment_program SSAO/ShowViewPos_fp cg
+{
+    source ShowViewPos.cg
+    entry_point ShowViewPos_fp
+    profiles ps_2_0 arbfp1
+}
+
+material SSAO/ShowViewPos
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/ShowViewPos_fp {}
+
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/UnsharpMask.cg

View file
+void UnsharpMask_fp
+(
+    in float2 iTexCoord : TEXCOORD0, 
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler blurred: register(s0),
+    uniform sampler mrt0: register(s1),
+    uniform sampler mrt1: register(s2),
+    uniform float cLambda
+)
+{
+    float spacialImportance = tex2D(blurred, iTexCoord).w - tex2D(mrt1, iTexCoord).w;
+    float4 color = tex2D(mrt0, iTexCoord);
+    if (spacialImportance < 0) // darkening only
+    {
+        oColor0 = float4(color.rgb + (cLambda * spacialImportance), 1);
+    } else 
+    {
+        oColor0 = color;
+    }
+}
+
+void GaussianBlurX_fp
+(
+    in float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler mrt1 : register(s0),
+    uniform float stepX,
+    uniform const float cKernelWidthBias
+)
+{
+    const int kernelWidth = 19;
+    float sigma = (kernelWidth - 1) / 6; // make the kernel span 6 sigma
+
+    float weights = 0;
+    float blurredDepth = 0;
+    
+    for (float i = -(kernelWidth - 1) / 2; i < (kernelWidth - 1) / 2; i++)
+    {
+        float geometricWeight = exp(-pow(i, 2) / (2 * pow(sigma, 2)));
+        weights += geometricWeight;
+        blurredDepth += tex2D(mrt1, float2(uv.x - i * stepX * cKernelWidthBias, uv.y)).w * geometricWeight;
+    }
+
+    blurredDepth /= weights;
+    oColor0 = float4(tex2D(mrt1, uv).xyz, blurredDepth);
+}
+
+void GaussianBlurY_fp
+(
+    in float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler mrt1 : register(s0),
+    uniform const float stepY,
+    uniform const float cKernelWidthBias
+)
+{
+    const int kernelWidth = 19;
+    float sigma = (kernelWidth - 1) / 6; // make the kernel span 6 sigma
+
+    float weights = 0;
+    float blurredDepth = 0;
+    
+    for (float i = -(kernelWidth - 1) / 2; i < (kernelWidth - 1) / 2; i++)
+    {
+        float geometricWeight = exp(-pow(i, 2) / (2 * pow(sigma, 2)));
+        weights += geometricWeight;
+        blurredDepth += tex2D(mrt1, float2(uv.x, uv.y - i * stepY * cKernelWidthBias)).w * geometricWeight;
+    }
+
+    blurredDepth /= weights;
+    oColor0 = float4(tex2D(mrt1, uv).xyz, blurredDepth);
+}
+    

File Samples/Media/materials/scripts/SSAO/UnsharpMask.material

View file
+fragment_program SSAO/UnsharpMask_fp cg
+{
+    source UnsharpMask.cg
+    entry_point UnsharpMask_fp
+    profiles ps_2_0 arbfp1
+}
+
+fragment_program SSAO/UnsharpMask/GaussianBlurX_fp cg
+{
+    source UnsharpMask.cg
+    entry_point GaussianBlurX_fp
+    profiles ps_2_0 arbfp1
+}
+
+fragment_program SSAO/UnsharpMask/GaussianBlurY_fp cg
+{
+    source UnsharpMask.cg
+    entry_point GaussianBlurY_fp
+    profiles ps_2_0 arbfp1
+}
+
+material SSAO/UnsharpMask/GaussianBlurX
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+            
+            fragment_program_ref SSAO/UnsharpMask/GaussianBlurX_fp
+            {
+                param_named_auto stepX inverse_viewport_width
+            }
+            
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}
+
+material SSAO/UnsharpMask/GaussianBlurY
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+        
+            fragment_program_ref SSAO/UnsharpMask/GaussianBlurY_fp
+            {
+                param_named_auto stepY inverse_viewport_height
+            }
+            
+            texture_unit
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}
+
+material SSAO/UnsharpMask
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+
+            fragment_program_ref SSAO/UnsharpMask_fp {}
+            
+            texture_unit // blurred depth buffer
+            {
+                tex_address_mode clamp
+                filtering none
+            }
+            
+            texture_unit // color component of the GBuffer
+            {
+                content_type compositor SSAO/GBuffer mrt 0
+                tex_address_mode clamp
+                filtering none
+            }
+
+            texture_unit // original depth buffer
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/scripts/SSAO/Volumetric.cg

View file
+void Volumetric_fp
+(
+    in const float2 uv : TEXCOORD0,
+    
+    out float4 oColor0 : COLOR0,
+    
+    uniform sampler sMRT1 : register(s0), // fragment normals
+    uniform sampler sMRT2 : register(s1), // view space position, remember that we are looking down the negative Z axis!!!
+    uniform sampler sRand : register(s2),
+    
+    uniform const float4 cViewportSize, // (viewport_width, viewport_height, inverse_viewport_width, inverse_viewport_height)
+    uniform const float cFov, // vertical field of view in radians
+    uniform const float cSampleInScreenspace, // whether to sample in screen or world space
+    uniform const float cSampleLengthScreenSpace, // The sample length in screen space [0, 1]
+    uniform const float cSampleLengthWorldSpace // the sample length in world space in units
+)
+{
+    const int interleaved = 4;
+    const int m = 8;
+    const int n = 4;
+    const int numSamples = m * n;    
+
+    const float2 interleaveOffset = uv * cViewportSize.xy / interleaved;
+    
+    const float3 fragmentPosition = tex2D(sMRT2, uv).xyz; // the current fragment in view space
+    const float3 fragmentNormal = tex2D(sMRT1, uv).xyz * float3(1, -1, 1); // the fragment normal
+
+    float rUV = 0; // radius of influence in screen space
+    float r = 0; // radius of influence in world space
+    if (cSampleInScreenspace == 1)
+    {
+        rUV = cSampleLengthScreenSpace;
+        r = tan(rUV * cFov) * -fragmentPosition.z;
+    }
+    else
+    {
+        rUV = atan(cSampleLengthWorldSpace / -fragmentPosition.z) / cFov; // the radius of influence projected into screen space
+        r = cSampleLengthWorldSpace;
+    }
+
+
+    if (rUV < (cViewportSize.z)) // abort if the projected radius of influence is smaller than 1 fragment
+    {
+        oColor0 = 1;
+        return;
+    }
+    
+    const float r2 = r/2;
+    const float rUV2 = rUV /2;
+    
+    const float3 center = fragmentPosition + fragmentNormal * (r2);
+    const float2 centerUV = uv + fragmentNormal * (rUV2);
+
+    float F = 0; // unoccluded Volume
+    float V = 0; // occluded Volume
+    float invalid = 0;
+
+    for (float i = 0.0f; i < m; i++)
+    for (float j = 0.0f; j < n; j++)
+    {
+        const float2 randomTC = interleaveOffset + float2(i/(interleaved * m), j/(interleaved * n)); 
+        const float2 randomVector = (tex2D(sRand, randomTC) * 2 - 1).xy; // unpack to [-1, 1]^2
+
+        const float2 sample = randomVector * (r2);
+        const float2 sampleUV = randomVector * (rUV2);
+
+        const float zEntry = center.z + (r2) * sqrt(1 - sample.x * sample.x - sample.y * sample.y);
+        const float zExit = center.z - (r2) * sqrt(1 - sample.x * sample.x - sample.y * sample.y);
+        const float zStar = tex2D(sMRT2, centerUV + sampleUV).z;
+
+        F += zExit - zEntry;
+
+        if (zExit <= zStar && zStar <= zEntry)
+            V += zStar - zEntry;
+        else //if (zStar < zExit)
+            V += zExit - zEntry;
+    }
+
+    float accessibility = V / F;
+    oColor0 = float4(accessibility.xxx, 1);
+
+}

File Samples/Media/materials/scripts/SSAO/Volumetric.material

View file
+fragment_program SSAO/Volumetric_fp cg
+{
+    source Volumetric.cg
+    entry_point Volumetric_fp
+    profiles arbfp1 ps_3_0
+}
+
+
+material SSAO/Volumetric
+{
+    technique
+    {
+        pass
+        {
+            depth_check off
+            
+            fragment_program_ref SSAO/Volumetric_fp
+            {
+                param_named_auto cViewportSize viewport_size
+                param_named_auto cFov fov
+            }
+            
+            texture_unit // normals
+            {
+                content_type compositor SSAO/GBuffer mrt 1
+                tex_address_mode clamp
+                filtering none
+            }
+            
+            texture_unit // view space position
+            {
+                content_type compositor SSAO/GBuffer mrt 2
+                tex_address_mode clamp
+                filtering none
+            }
+            
+            texture_unit
+            {
+                texture 4InterleavedKMeansDisk8x4.png
+                tex_address_mode wrap
+                filtering none
+            }
+        }
+    }
+}

File Samples/Media/materials/textures/SSAO/4InterleavedKMeansDisk8x4.png

Added
New image

File Samples/Media/materials/textures/SSAO/gray256.png

Added
New image

File Samples/Media/materials/textures/SSAO/importance4InterleavedSphereHemisphere8x4.png

Added
New image

File Samples/Media/materials/textures/SSAO/rand1x32.png

Added
New image

File Samples/Media/materials/textures/SSAO/randCosSinJitter4x4.png

Added
New image

File Samples/Media/materials/textures/SSAO/regularSphereJittered4.png

Added
New image

File Samples/Media/models/cornell.mesh

Binary file added.

File Samples/Media/thumbnails/thumb_ssao.png

Added
New image

File Samples/SSAO/CMakeLists.txt

View file