1void Volumetric_fp
2(
3    in const float2 uv : TEXCOORD0,
4
5    out float4 oColor0 : COLOR0,
6
7    uniform sampler sMRT1 : register(s0), // fragment normals
8    uniform sampler sMRT2 : register(s1), // view space position, remember that we are looking down the negative Z axis!!!
9    uniform sampler sRand : register(s2),
10
11    uniform const float4 cViewportSize, // (viewport_width, viewport_height, inverse_viewport_width, inverse_viewport_height)
12    uniform const float cFov, // vertical field of view in radians
13    uniform const float cSampleInScreenspace, // whether to sample in screen or world space
14    uniform const float cSampleLengthScreenSpace, // The sample length in screen space [0, 1]
15    uniform const float cSampleLengthWorldSpace // the sample length in world space in units
16)
17{
18    const int interleaved = 4;
19    const int m = 8;
20    const int n = 4;
21    const int numSamples = m * n;
22
23    const float2 interleaveOffset = uv * cViewportSize.xy / interleaved;
24
25    const float3 fragmentPosition = tex2D(sMRT2, uv).xyz; // the current fragment in view space
26    const float3 fragmentNormal = tex2D(sMRT1, uv).xyz * float3(1, -1, 1); // the fragment normal
27
28    float rUV = 0; // radius of influence in screen space
29    float r = 0; // radius of influence in world space
30    if (cSampleInScreenspace == 1)
31    {
32        rUV = cSampleLengthScreenSpace;
33        r = tan(rUV * cFov) * -fragmentPosition.z;
34    }
35    else
36    {
37        rUV = atan(cSampleLengthWorldSpace / -fragmentPosition.z) / cFov; // the radius of influence projected into screen space
38        r = cSampleLengthWorldSpace;
39    }
40
41
42    if (rUV < (cViewportSize.z)) // abort if the projected radius of influence is smaller than 1 fragment
43    {
44        oColor0 = 1;
45        return;
46    }
47
48    const float r2 = r/2;
49    const float rUV2 = rUV /2;
50
51    const float3 center = fragmentPosition + fragmentNormal * (r2);
52    const float2 centerUV = uv + fragmentNormal * (rUV2);
53
54    float F = 0; // unoccluded Volume
55    float V = 0; // occluded Volume
56    float invalid = 0;
57
58    for (float i = 0.0f; i < m; i++)
59    for (float j = 0.0f; j < n; j++)
60    {
61        const float2 randomTC = interleaveOffset + float2(i/(interleaved * m), j/(interleaved * n));
62        const float2 randomVector = (tex2D(sRand, randomTC) * 2 - 1).xy; // unpack to [-1, 1]^2
63
64        const float2 sample = randomVector * (r2);
65        const float2 sampleUV = randomVector * (rUV2);
66
67        const float zEntry = center.z + (r2) * sqrt(1 - sample.x * sample.x - sample.y * sample.y);
68        const float zExit = center.z - (r2) * sqrt(1 - sample.x * sample.x - sample.y * sample.y);
69        const float zStar = tex2D(sMRT2, centerUV + sampleUV).z;
70
71        F += zExit - zEntry;
72
73        if (zExit <= zStar && zStar <= zEntry)
74            V += zStar - zEntry;
75        else //if (zStar < zExit)
76            V += zExit - zEntry;
77    }
78
79    float accessibility = V / F;
80    oColor0 = float4(accessibility.xxx, 1);
81
82}
83