1 | ///////////////////////////////////////////////////////////////////////////////// |
---|
2 | // |
---|
3 | // shadowreceiverfp.cg |
---|
4 | // |
---|
5 | // Hamilton Chong |
---|
6 | // (c) 2006 |
---|
7 | // |
---|
8 | // This is an example fragment shader for shadow receiver objects. |
---|
9 | // |
---|
10 | ///////////////////////////////////////////////////////////////////////////////// |
---|
11 | |
---|
12 | |
---|
13 | sampler2D ShadowMap : TEXUNIT0; |
---|
14 | |
---|
15 | // Define outputs from vertex shader. |
---|
16 | struct Vertex |
---|
17 | { |
---|
18 | float4 position : POSITION; // fragment position in post projective space |
---|
19 | float4 shadowCoord : TEXCOORD0; // fragment position in shadow map coordinates |
---|
20 | float diffuse : TEXCOORD1; // diffuse shading value |
---|
21 | }; |
---|
22 | |
---|
23 | struct Fragment |
---|
24 | { |
---|
25 | float4 color : COLOR0; |
---|
26 | }; |
---|
27 | |
---|
28 | Fragment main(Vertex In, |
---|
29 | uniform float uSTexWidth, |
---|
30 | uniform float uSTexHeight) |
---|
31 | { |
---|
32 | Fragment Out; |
---|
33 | |
---|
34 | // compute the shadow coordinates for texture lookup |
---|
35 | // NOTE: texture_viewproj_matrix maps z into [0,1] range, not [-1,1], so |
---|
36 | // have to make sure shadow caster stores depth values with same convention. |
---|
37 | float4 scoord = In.shadowCoord / In.shadowCoord.w; |
---|
38 | |
---|
39 | |
---|
40 | // -- Bilinear Filtering of Sample -------------------------------------------- |
---|
41 | |
---|
42 | // One could use scoord.xy to look up the shadow map for depth testing, but |
---|
43 | // we'll be implementing a simple "percentage closest filtering" algorithm instead. |
---|
44 | // This mimics the behavior of turning on bilinear filtering on NVIDIA hardware |
---|
45 | // when also performing shadow comparisons. This causes bilinear filtering of |
---|
46 | // depth tests. Note that this is NOT the same as bilinear filtering the depth |
---|
47 | // values and then doing the depth comparison. The two operations are not |
---|
48 | // commutative. PCF is explicitly about filtering the test values since |
---|
49 | // testing filtered z values is often meaningless. |
---|
50 | |
---|
51 | // Real percentage closest filtering should sample from the entire footprint |
---|
52 | // on the shadow map, not just seek the closest four sample points. Such |
---|
53 | // an improvement is for future work. |
---|
54 | |
---|
55 | |
---|
56 | // NOTE: Assuming OpenGL convention for texture lookups with integers in centers. |
---|
57 | // DX convention is to have integers mark sample corners |
---|
58 | float2 tcoord; |
---|
59 | tcoord.x = (scoord.x * uSTexWidth) - 0.5; |
---|
60 | tcoord.y = (scoord.y * uSTexHeight) - 0.5; |
---|
61 | float x0 = floor(tcoord.x); |
---|
62 | float x1 = ceil(tcoord.x); |
---|
63 | float fracx = frac(tcoord.x); |
---|
64 | float y0 = floor(tcoord.y); |
---|
65 | float y1 = ceil(tcoord.y); |
---|
66 | float fracy = frac(tcoord.y); |
---|
67 | |
---|
68 | // sample coordinates in [0,1]^2 domain |
---|
69 | float2 t00, t01, t10, t11; |
---|
70 | float invWidth = 1.0 / uSTexWidth; |
---|
71 | float invHeight = 1.0 / uSTexHeight; |
---|
72 | t00 = float2((x0+0.5) * invWidth, (y0+0.5) * invHeight); |
---|
73 | t10 = float2((x1+0.5) * invWidth, (y0+0.5) * invHeight); |
---|
74 | t01 = float2((x0+0.5) * invWidth, (y1+0.5) * invHeight); |
---|
75 | t11 = float2((x1+0.5) * invWidth, (y1+0.5) * invHeight); |
---|
76 | |
---|
77 | // grab the samples |
---|
78 | float2 z00 = tex2D(ShadowMap, t00).xy; |
---|
79 | float2 z01 = tex2D(ShadowMap, t01).xy; |
---|
80 | float2 z10 = tex2D(ShadowMap, t10).xy; |
---|
81 | float2 z11 = tex2D(ShadowMap, t11).xy; |
---|
82 | |
---|
83 | // bilinear filter the sample data |
---|
84 | float2 d0 = ((1.0 - fracx) * z00) + (fracx * z10); |
---|
85 | float2 d1 = ((1.0 - fracx) * z01) + (fracx * z11); |
---|
86 | float2 datum = ((1.0 - fracy) * d0) + (fracy * d1); |
---|
87 | |
---|
88 | // -- Variance Shadow Mapping --------------------------------------------------- |
---|
89 | |
---|
90 | float zVariance = datum.y - (datum.x * datum.x); |
---|
91 | float zDeviation = scoord.z - datum.x; |
---|
92 | zDeviation = (zDeviation < 0.0) ? 0.0 : zDeviation; |
---|
93 | float visibility = zVariance / (zVariance + (zDeviation * zDeviation)); |
---|
94 | float ztest = (scoord.z < datum.x) ? 1.0:0.0; // filtering depth ok, because used only for small variance |
---|
95 | visibility = (zVariance > 0.0) ? visibility : ztest; // if variance too small, we get garbage |
---|
96 | //0.0000001 |
---|
97 | |
---|
98 | // determine that all geometry within pixel border of shadow map (and outside) is lit |
---|
99 | float filterBorder = max(invWidth, invHeight); |
---|
100 | visibility = (all(abs(scoord.xy-0.5)<=0.5-filterBorder)) ? visibility : 1.0; |
---|
101 | |
---|
102 | // ------------------------------------------------------------------------------ |
---|
103 | |
---|
104 | visibility *= In.diffuse; |
---|
105 | Out.color = float4(visibility, visibility, visibility, 0.0); |
---|
106 | return Out; |
---|
107 | } |
---|