A game about forced loneliness, made by TACStudios
1#ifndef SHADOW_SAMPLING_TENT_INCLUDED
2#define SHADOW_SAMPLING_TENT_INCLUDED
3// ------------------------------------------------------------------
4// PCF Filtering Tent Functions
5// ------------------------------------------------------------------
6
7// Assuming a isoceles right angled triangle of height "triangleHeight" (as drawn below).
8// This function return the area of the triangle above the first texel.
9//
10// |\ <-- 45 degree slop isosceles right angled triangle
11// | \
12// ---- <-- length of this side is "triangleHeight"
13// _ _ _ _ <-- texels
14real SampleShadow_GetTriangleTexelArea(real triangleHeight)
15{
16 return triangleHeight - 0.5;
17}
18
19// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
20// This function return the area of the triangle above each of those texels.
21// | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center
22// / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)
23// / \
24// _ _ _ _ <-- texels
25// X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)
26void SampleShadow_GetTexelAreas_Tent_3x3(real offset, out real4 computedArea, out real4 computedAreaUncut)
27{
28 // Compute the exterior areas
29 real offset01SquaredHalved = (offset + 0.5) * (offset + 0.5) * 0.5;
30 computedAreaUncut.x = computedArea.x = offset01SquaredHalved - offset;
31 computedAreaUncut.w = computedArea.w = offset01SquaredHalved;
32
33 // Compute the middle areas
34 // For Y : We find the area in Y of as if the left section of the isoceles triangle would
35 // intersect the axis between Y and Z (ie where offset = 0).
36 computedAreaUncut.y = SampleShadow_GetTriangleTexelArea(1.5 - offset);
37 // This area is superior to the one we are looking for if (offset < 0) thus we need to
38 // subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).
39 real clampedOffsetLeft = min(offset,0);
40 real areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;
41 computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;
42
43 // We do the same for the Z but with the right part of the isoceles triangle
44 computedAreaUncut.z = SampleShadow_GetTriangleTexelArea(1.5 + offset);
45 real clampedOffsetRight = max(offset,0);
46 real areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;
47 computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;
48}
49
50// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
51// This function return the weight of each texels area relative to the full triangle area.
52void SampleShadow_GetTexelWeights_Tent_3x3(real offset, out real4 computedWeight)
53{
54 real4 dummy;
55 SampleShadow_GetTexelAreas_Tent_3x3(offset, computedWeight, dummy);
56 computedWeight *= 0.44444;//0.44 == 1/(the triangle area)
57}
58
59// Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.
60// This function return the weight of each texels area relative to the full triangle area.
61// / \
62// _ _ _ _ _ _ <-- texels
63// 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])
64void SampleShadow_GetTexelWeights_Tent_5x5(real offset, out real3 texelsWeightsA, out real3 texelsWeightsB)
65{
66 // See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
67 real4 computedArea_From3texelTriangle;
68 real4 computedAreaUncut_From3texelTriangle;
69 SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
70
71 // Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
72 // the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.
73 // 0.16 is 1/(the triangle area)
74 texelsWeightsA.x = 0.16 * (computedArea_From3texelTriangle.x);
75 texelsWeightsA.y = 0.16 * (computedAreaUncut_From3texelTriangle.y);
76 texelsWeightsA.z = 0.16 * (computedArea_From3texelTriangle.y + 1);
77 texelsWeightsB.x = 0.16 * (computedArea_From3texelTriangle.z + 1);
78 texelsWeightsB.y = 0.16 * (computedAreaUncut_From3texelTriangle.z);
79 texelsWeightsB.z = 0.16 * (computedArea_From3texelTriangle.w);
80}
81
82// Assuming a isoceles triangle of 3.5 texel height and 7 texels wide lying on 8 texels.
83// This function return the weight of each texels area relative to the full triangle area.
84// / \
85// _ _ _ _ _ _ _ _ <-- texels
86// 0 1 2 3 4 5 6 7 <-- computed area indices (in texelsWeights[])
87void SampleShadow_GetTexelWeights_Tent_7x7(real offset, out real4 texelsWeightsA, out real4 texelsWeightsB)
88{
89 // See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
90 real4 computedArea_From3texelTriangle;
91 real4 computedAreaUncut_From3texelTriangle;
92 SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
93
94 // Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
95 // the 7 texel wide triangle can be seen as the 3 texel wide one but shifted up by two unit/texel.
96 // 0.081632 is 1/(the triangle area)
97 texelsWeightsA.x = 0.081632 * (computedArea_From3texelTriangle.x);
98 texelsWeightsA.y = 0.081632 * (computedAreaUncut_From3texelTriangle.y);
99 texelsWeightsA.z = 0.081632 * (computedAreaUncut_From3texelTriangle.y + 1);
100 texelsWeightsA.w = 0.081632 * (computedArea_From3texelTriangle.y + 2);
101 texelsWeightsB.x = 0.081632 * (computedArea_From3texelTriangle.z + 2);
102 texelsWeightsB.y = 0.081632 * (computedAreaUncut_From3texelTriangle.z + 1);
103 texelsWeightsB.z = 0.081632 * (computedAreaUncut_From3texelTriangle.z);
104 texelsWeightsB.w = 0.081632 * (computedArea_From3texelTriangle.w);
105}
106
107// 3x3 Tent filter (45 degree sloped triangles in U and V)
108void SampleShadow_ComputeSamples_Tent_3x3(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[4], out real2 fetchesUV[4])
109{
110 // tent base is 3x3 base thus covering from 9 to 12 texels, thus we need 4 bilinear PCF fetches
111 real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
112 real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
113 real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
114
115 // find the weight of each texel based
116 real4 texelsWeightsU, texelsWeightsV;
117 SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU);
118 SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV);
119
120 // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
121 real2 fetchesWeightsU = texelsWeightsU.xz + texelsWeightsU.yw;
122 real2 fetchesWeightsV = texelsWeightsV.xz + texelsWeightsV.yw;
123
124 // move the PCF bilinear fetches to respect texels weights
125 real2 fetchesOffsetsU = texelsWeightsU.yw / fetchesWeightsU.xy + real2(-1.5,0.5);
126 real2 fetchesOffsetsV = texelsWeightsV.yw / fetchesWeightsV.xy + real2(-1.5,0.5);
127 fetchesOffsetsU *= shadowMapTexture_TexelSize.xx;
128 fetchesOffsetsV *= shadowMapTexture_TexelSize.yy;
129
130 real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
131 fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
132 fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
133 fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
134 fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
135
136 fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
137 fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
138 fetchesWeights[2] = fetchesWeightsU.x * fetchesWeightsV.y;
139 fetchesWeights[3] = fetchesWeightsU.y * fetchesWeightsV.y;
140}
141
142// 5x5 Tent filter (45 degree sloped triangles in U and V)
143void SampleShadow_ComputeSamples_Tent_5x5(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[9], out real2 fetchesUV[9])
144{
145 // tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches
146 real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
147 real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
148 real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
149
150 // find the weight of each texel based on the area of a 45 degree slop tent above each of them.
151 real3 texelsWeightsU_A, texelsWeightsU_B;
152 real3 texelsWeightsV_A, texelsWeightsV_B;
153 SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
154 SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
155
156 // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
157 real3 fetchesWeightsU = real3(texelsWeightsU_A.xz, texelsWeightsU_B.y) + real3(texelsWeightsU_A.y, texelsWeightsU_B.xz);
158 real3 fetchesWeightsV = real3(texelsWeightsV_A.xz, texelsWeightsV_B.y) + real3(texelsWeightsV_A.y, texelsWeightsV_B.xz);
159
160 // move the PCF bilinear fetches to respect texels weights
161 real3 fetchesOffsetsU = real3(texelsWeightsU_A.y, texelsWeightsU_B.xz) / fetchesWeightsU.xyz + real3(-2.5,-0.5,1.5);
162 real3 fetchesOffsetsV = real3(texelsWeightsV_A.y, texelsWeightsV_B.xz) / fetchesWeightsV.xyz + real3(-2.5,-0.5,1.5);
163 fetchesOffsetsU *= shadowMapTexture_TexelSize.xxx;
164 fetchesOffsetsV *= shadowMapTexture_TexelSize.yyy;
165
166 real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
167 fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
168 fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
169 fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
170 fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
171 fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
172 fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
173 fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
174 fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
175 fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
176
177 fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
178 fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
179 fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
180 fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y;
181 fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y;
182 fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y;
183 fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z;
184 fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z;
185 fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z;
186}
187
188// 7x7 Tent filter (45 degree sloped triangles in U and V)
189void SampleShadow_ComputeSamples_Tent_7x7(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[16], out real2 fetchesUV[16])
190{
191 // tent base is 7x7 base thus covering from 49 to 64 texels, thus we need 16 bilinear PCF fetches
192 real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
193 real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
194 real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
195
196 // find the weight of each texel based on the area of a 45 degree slop tent above each of them.
197 real4 texelsWeightsU_A, texelsWeightsU_B;
198 real4 texelsWeightsV_A, texelsWeightsV_B;
199 SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
200 SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
201
202 // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
203 real4 fetchesWeightsU = real4(texelsWeightsU_A.xz, texelsWeightsU_B.xz) + real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw);
204 real4 fetchesWeightsV = real4(texelsWeightsV_A.xz, texelsWeightsV_B.xz) + real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw);
205
206 // move the PCF bilinear fetches to respect texels weights
207 real4 fetchesOffsetsU = real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw) / fetchesWeightsU.xyzw + real4(-3.5,-1.5,0.5,2.5);
208 real4 fetchesOffsetsV = real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw) / fetchesWeightsV.xyzw + real4(-3.5,-1.5,0.5,2.5);
209 fetchesOffsetsU *= shadowMapTexture_TexelSize.xxxx;
210 fetchesOffsetsV *= shadowMapTexture_TexelSize.yyyy;
211
212 real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
213 fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
214 fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
215 fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
216 fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.x);
217 fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
218 fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
219 fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
220 fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.y);
221 fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
222 fetchesUV[9] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
223 fetchesUV[10] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
224 fetchesUV[11] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.z);
225 fetchesUV[12] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.w);
226 fetchesUV[13] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.w);
227 fetchesUV[14] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.w);
228 fetchesUV[15] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.w);
229
230 fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
231 fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
232 fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
233 fetchesWeights[3] = fetchesWeightsU.w * fetchesWeightsV.x;
234 fetchesWeights[4] = fetchesWeightsU.x * fetchesWeightsV.y;
235 fetchesWeights[5] = fetchesWeightsU.y * fetchesWeightsV.y;
236 fetchesWeights[6] = fetchesWeightsU.z * fetchesWeightsV.y;
237 fetchesWeights[7] = fetchesWeightsU.w * fetchesWeightsV.y;
238 fetchesWeights[8] = fetchesWeightsU.x * fetchesWeightsV.z;
239 fetchesWeights[9] = fetchesWeightsU.y * fetchesWeightsV.z;
240 fetchesWeights[10] = fetchesWeightsU.z * fetchesWeightsV.z;
241 fetchesWeights[11] = fetchesWeightsU.w * fetchesWeightsV.z;
242 fetchesWeights[12] = fetchesWeightsU.x * fetchesWeightsV.w;
243 fetchesWeights[13] = fetchesWeightsU.y * fetchesWeightsV.w;
244 fetchesWeights[14] = fetchesWeightsU.z * fetchesWeightsV.w;
245 fetchesWeights[15] = fetchesWeightsU.w * fetchesWeightsV.w;
246}
247#endif