A game about forced loneliness, made by TACStudios
at master 247 lines 15 kB view raw
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