Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define NUM_SAMPLES (8)
- static const int ROTATIONS[] = { 1, 1, 2, 3, 2, 5, 2, 3, 2,
- 3, 3, 5, 5, 3, 4, 7, 5, 5, 7,
- 9, 8, 5, 5, 7, 7, 7, 8, 5, 8,
- 11, 12, 7, 10, 13, 8, 11, 8, 7, 14,
- 11, 11, 13, 12, 13, 19, 17, 13, 11, 18,
- 19, 11, 11, 14, 17, 21, 15, 16, 17, 18,
- 13, 17, 11, 17, 19, 18, 25, 18, 19, 19,
- 29, 21, 19, 27, 31, 29, 21, 18, 17, 29,
- 31, 31, 23, 18, 25, 26, 25, 23, 19, 34,
- 19, 27, 21, 25, 39, 29, 17, 21, 27 };
- /** Used for preventing AO computation on the sky (at infinite depth) and defining the CS Z to bilateral depth key scaling.
- This need not match the real far plane*/
- #define FAR_PLANE_Z (90.0)
- // This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent
- // taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9
- static const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES-1];
- /** World-space AO radius in scene units (r). e.g., 1.0m */
- static const float radius = 0.7;
- /** radius*radius*/
- static const float radius2 = (radius*radius);
- /** Bias to avoid AO in smooth corners, e.g., 0.01m */
- static const float bias = 0.02f;
- /** The height in pixels of a 1m object if viewed from 1m away.
- You can compute it from your projection matrix. The actual value is just
- a scale factor on radius; you can simply hardcode this to a constant (~500)
- and make your radius value unitless (...but resolution dependent.) */
- static const float projScale = 500.0f;
- static const float nearZ = 0.001;
- static const float farZ = 1.0;
- float4 g_ReprojectInfoFromInt;
- // Texture2D<float> InputTextureLinearDepth : register(t0);
- // Texture2D<float4> InputTextureSSAO : register(t1);
- // Texture2D<float2> InputTextureMotion : register(t2);
- texture2D depthTex2D;
- sampler depthSampler = sampler_state
- {
- texture = <depthTex2D>;
- MinFilter = POINT;
- MagFilter = POINT;
- MipFilter = POINT;
- AddressU = Mirror;
- AddressV = Mirror;
- SRGBTexture=FALSE;
- };
- texture2D frameTex2D;
- sampler frameSampler = sampler_state
- {
- texture = <frameTex2D>;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- MipFilter = LINEAR;
- AddressU = Clamp;
- AddressV = Clamp;
- SRGBTexture = FALSE;
- };
- texture2D prevPassTex2D;
- sampler passSampler = sampler_state
- {
- texture = <prevPassTex2D>;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- MipFilter = LINEAR;
- AddressU = Clamp;
- AddressV = Clamp;
- SRGBTexture=FALSE;
- };
- texture2D noiseTexture < string filename = "RandomNoiseB.dds"; >;
- sampler2D noiseSampler = sampler_state {
- texture = <noiseTexture>;
- AddressU = WRAP;
- AddressV = WRAP;
- MINFILTER = LINEAR;
- MAGFILTER = LINEAR;
- MIPFILTER = LINEAR;
- };
- struct VSOUT
- {
- float4 vertPos : POSITION0;
- float2 UVCoord : TEXCOORD0;
- };
- struct VSIN
- {
- float4 vertPos : POSITION0;
- float2 UVCoord : TEXCOORD0;
- };
- VSOUT FrameVS(VSIN IN)
- {
- VSOUT OUT;
- float4 pos=float4(IN.vertPos.x, IN.vertPos.y, IN.vertPos.z, 1.0f);
- OUT.vertPos=pos;
- float2 coord=float2(IN.UVCoord.x, IN.UVCoord.y);
- OUT.UVCoord=coord;
- return OUT;
- }
- /** Reconstruct camera-space P.xyz from screen-space S = (x, y) in
- pixels and camera-space z < 0. Assumes that the upper-left pixel center
- is at (0.5, 0.5) [but that need not be the location at which the sample tap
- was placed!]
- */
- // Projection Matrix as generated in the .cpp code ( not sure if it works :/ ) ------------------------
- // D3DXVECTOR4 g_ReprojectInfoFromInt;
- // unsigned width, height;
- // width = 1280; height = 720;
- // g_ReprojectInfoFromInt.x = -2.0f / ((float)(float)width*((float)height / (float)width));
- // g_ReprojectInfoFromInt.y = -2.0f / (float)height*1.0;
- // g_ReprojectInfoFromInt.z = (1.0f - 0.0) / ((float)(float)height / (float)width) + g_ReprojectInfoFromInt.x * 0.5f;
- // g_ReprojectInfoFromInt.w = (1.0f + 0.0) / 1.0 + g_ReprojectInfoFromInt.y * 0.5f;
- // HRESULT hr = effect->SetVector(projectionHandle, &g_ReprojectInfoFromInt);
- float3 reconstructCSPosition(float2 S, float z)
- {
- return float3((S * g_ReprojectInfoFromInt.xy + g_ReprojectInfoFromInt.zw)*z, z);
- }
- /** Reconstructs screen-space unit normal from screen-space position */
- float3 reconstructCSFaceNormal(float3 C)
- {
- return normalize(cross(ddy(C), ddx(C)));
- }
- /** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */
- float2 tapLocation(int sampleNumber, float spinAngle, out float ssR)
- {
- // Radius relative to ssR
- float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES);
- float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle;
- ssR = alpha;
- float sin_v, cos_v;
- sincos(angle, sin_v, cos_v);
- return float2(cos_v, sin_v);
- }
- /** Used for packing Z into the GB channels */
- float CSZToKey(float z)
- {
- return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0);
- }
- /** Read the camera-space position of the point at screen-space pixel ssP */
- float3 getPosition(float2 ssP)
- {
- float3 P;
- P.z = (2.0f * nearZ) / ((farZ + nearZ) - tex2D(depthSampler, ssP).r * (farZ - nearZ));
- // Offset to pixel center
- P = reconstructCSPosition(float2(ssP), P.z);
- //P = reconstructCSPosition(float2(ssP) + float2(0.5, 0.5), P.z);
- return P;
- }
- /** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */
- float3 getOffsetPosition(float2 ssC, float2 unitOffset, float ssR)
- {
- float2 ssP = saturate(float2(ssR*unitOffset) + ssC);
- float3 P;
- // Divide coordinate by 2^mipLevel
- P.z = (2.0f * nearZ) / ((farZ + nearZ) - tex2D(depthSampler, ssP).r * (farZ - nearZ));
- // Offset to pixel center
- P = reconstructCSPosition(float2(ssP), P.z);
- //P = reconstructCSPosition(float2(ssP) + float2(0.5, 0.5), P.z);
- return P;
- }
- /** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds
- to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius */
- float sampleAO(in float2 ssC, in float3 C, in float3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle)
- {
- // Offset on the unit disk, spun for this pixel
- float ssR;
- float2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
- ssR *= ssDiskRadius;
- // The occluding point in camera space
- float3 Q = getOffsetPosition(ssC, unitOffset, ssR);
- float3 v = Q - C;
- float vv = dot(v, v);
- float vn = dot(v, n_C);
- const float epsilon = 0.02f;
- float f = max(radius2 - vv, 0.0);
- return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
- }
- /** Used for packing Z into the GB channels */
- void packKey(float key, out float2 p)
- {
- // Round to the nearest 1/256.0
- float temp = floor(key * 256.0);
- // Integer part
- p.x = temp * (1.0 / 256.0);
- // Fractional part
- p.y = key * 256.0 - temp;
- }
- float unpackKey(float2 p)
- {
- return p.x * (256.0 / 257.0) + p.y * (1.0 / 257.0);
- }
- #define visibility output.r
- #define bilateralKey output.gb
- float4 SSAOCalculate(VSOUT IN) : COLOR0
- {
- float4 output = float4(1,1,1,1);
- // Pixel being shaded
- float2 ssC = IN.UVCoord;
- // World space point being shaded
- float3 C = getPosition(ssC);
- return float4(C, 1.0);
- //return float4(IN.UVCoord, (2.0f * nearZ) / ((farZ + nearZ) - tex2D(depthSampler, IN.UVCoord).r * (farZ - nearZ)), 1.0);
- packKey(CSZToKey(C.z), bilateralKey);
- // Hash function used in the HPG12 AlchemyAO paper
- float randomPatternRotationAngle = tex2D(noiseSampler, ssC*12.0).x * 2.0;
- //return float4(randomPatternRotationAngle, randomPatternRotationAngle, randomPatternRotationAngle, 1.0);
- // Reconstruct normals from positions. These will lead to 1-pixel black lines
- // at depth discontinuities, however the blur will wipe those out so they are not visible
- // in the final image.
- float3 n_C = reconstructCSFaceNormal(C);
- //return float4(n_C, 1.0);
- // Choose the screen-space sample radius
- float ssDiskRadius = projScale * radius / max(C.z,0.1f);
- float sum = 0.0;
- for (int i = 0; i < NUM_SAMPLES; ++i)
- {
- sum += sampleAO(ssC, C, n_C, ssDiskRadius, i, randomPatternRotationAngle);
- }
- const float temp = radius2 * radius;
- sum /= temp * temp;
- float A = max(0.0f, 1.0f - sum * 1.0f * (5.0f / NUM_SAMPLES));
- visibility = A;
- //return float4(sum, sum, sum, 1.0);
- return output;
- }
- /** Increase to make edges crisper. Decrease to reduce temporal flicker. */
- #define EDGE_SHARPNESS (1.0)
- /** Step in 2-pixel intervals since we already blurred against neighbors in the
- first AO pass. This constant can be increased while R decreases to improve
- performance at the expense of some dithering artifacts.
- Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
- unobjectionable after shading was applied but eliminated most temporal incoherence
- from using small numbers of sample taps.
- */
- #define SCALE (2)
- /** Filter radius in pixels. This will be multiplied by SCALE. */
- #define R (3)
- //////////////////////////////////////////////////////////////////////////////////////////////
- /** Type of data to read from source. This macro allows
- the same blur shader to be used on different kinds of input data. */
- #define VALUE_TYPE float
- /** Swizzle to use to extract the channels of source. This macro allows
- the same blur shader to be used on different kinds of input data. */
- #define VALUE_COMPONENTS r
- #define VALUE_IS_KEY 0
- /** Channel encoding the bilateral key value (which must not be the same as VALUE_COMPONENTS) */
- #define KEY_COMPONENTS gb
- // Gaussian coefficients
- static const float gaussian[] =
- // { 0.356642, 0.239400, 0.072410, 0.009869 };
- // { 0.398943, 0.241971, 0.053991, 0.004432, 0.000134 }; // stddev = 1.0
- // { 0.153170, 0.144893, 0.122649, 0.092902, 0.062970 }; // stddev = 2.0
- { 0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108 }; // stddev = 3.0
- #define result output.VALUE_COMPONENTS
- #define keyPassThrough output.KEY_COMPONENTS
- float4 HBlurSSAO(VSOUT IN) : COLOR0
- {
- // Pixel being shaded
- float2 ssC = IN.UVCoord;
- float4 output = 1.0f;
- float4 temp = tex2Dlod(passSampler, float4(ssC, 0, 0));
- keyPassThrough = temp.KEY_COMPONENTS;
- float key = unpackKey(temp.KEY_COMPONENTS);
- float sum = temp.VALUE_COMPONENTS;
- // [branch]
- // if (key == 1.0)
- // {
- // // Sky pixel (if you aren't using depth keying, disable this test)
- // result = sum;
- // return output;
- // }
- float BASE = gaussian[0];
- float totalWeight = BASE;
- sum *= totalWeight;
- [unroll]
- for (int r = -R; r <= R; ++r)
- {
- // We already handled the zero case above. This loop should be unrolled and the branch discarded
- if (r != 0)
- {
- float2 axis = float2(1, 0);
- temp = tex2Dlod( passSampler, float4(ssC + axis * (r * SCALE), 0, 0) );
- float tapKey = unpackKey(temp.KEY_COMPONENTS);
- float value = temp.VALUE_COMPONENTS;
- // spatial domain: offset gaussian tap
- float weight = gaussian[abs(r)];
- // range domain (the "bilateral" weight). As depth difference increases, decrease weight.
- weight *= max(0.0, 1.0 - (2000.0 * EDGE_SHARPNESS) * abs(tapKey - key));
- sum += value * weight;
- totalWeight += weight;
- }
- }
- const float epsilon = 0.0001;
- result = sum / (totalWeight + epsilon);
- return output;
- }
- float4 VBlurSSAO(VSOUT IN) : COLOR0
- {
- // Pixel being shaded
- float2 ssC = IN.UVCoord;
- float4 output = 1.0f;
- float4 temp = tex2Dlod(passSampler, float4(ssC, 0, 0));
- float key = unpackKey(temp.KEY_COMPONENTS);
- float sum = temp.VALUE_COMPONENTS;
- // [branch]
- // if (key == 1.0)
- // {
- // // Sky pixel (if you aren't using depth keying, disable this test)
- // result = sum;
- // return output;
- // }
- float BASE = gaussian[0];
- float totalWeight = BASE;
- sum *= totalWeight;
- [unroll]
- for (int r = -R; r <= R; ++r)
- {
- // We already handled the zero case above. This loop should be unrolled and the branch discarded
- if (r != 0)
- {
- float2 axis = float2(0, 1);
- temp = tex2Dlod( passSampler, float4(ssC + axis * (r * SCALE), 0, 0) );
- float tapKey = unpackKey(temp.KEY_COMPONENTS);
- float value = temp.VALUE_COMPONENTS;
- // spatial domain: offset gaussian tap
- float weight = gaussian[abs(r)];
- // range domain (the "bilateral" weight). As depth difference increases, decrease weight.
- weight *= max(0.0, 1.0 - (2000.0 * EDGE_SHARPNESS) * abs(tapKey - key));
- sum += value * weight;
- totalWeight += weight;
- }
- }
- const float epsilon = 0.0001;
- result = sum / (totalWeight + epsilon);
- return output;
- }
- technique t0
- {
- pass p0
- {
- VertexShader = compile vs_3_0 FrameVS();
- PixelShader = compile ps_3_0 SSAOCalculate();
- }
- pass p1
- {
- VertexShader = compile vs_3_0 FrameVS();
- PixelShader = compile ps_3_0 HBlurSSAO();
- }
- pass p2
- {
- VertexShader = compile vs_3_0 FrameVS();
- PixelShader = compile ps_3_0 VBlurSSAO();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement