IrradianceEvaluate.bsl 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #if MSAA
  2. #define MSAA_COUNT 2
  3. #else
  4. #define MSAA_COUNT 1
  5. #endif
  6. #include "$ENGINE$\PPBase.bslinc"
  7. #define SH_ORDER 3
  8. #include "$ENGINE$\SHCommon.bslinc"
  9. #include "$ENGINE$\GBufferInput.bslinc"
  10. #include "$ENGINE$\PerCameraData.bslinc"
  11. shader IrradianceEvaluate
  12. {
  13. mixin PPBase;
  14. mixin SHCommon;
  15. mixin GBufferInput;
  16. mixin PerCameraData;
  17. variations
  18. {
  19. MSAA = { true, false };
  20. MSAA_RESOLVE_0TH = { true, false };
  21. SKY_ONLY = { true, false };
  22. };
  23. blend
  24. {
  25. target
  26. {
  27. enabled = true;
  28. color = { one, one, add };
  29. };
  30. };
  31. code
  32. {
  33. #if MSAA_COUNT > 1
  34. Texture2DMS<uint> gInputTex;
  35. #else
  36. Texture2D<uint> gInputTex;
  37. #endif
  38. struct Tetrahedron
  39. {
  40. uint4 indices;
  41. uint2 offsets[4];
  42. float3x4 transform;
  43. };
  44. struct TetrahedronFace
  45. {
  46. float4 corners[3];
  47. float4 normals[3];
  48. uint isQuadratic;
  49. float padding[3];
  50. };
  51. Texture2D gSHCoeffs;
  52. Buffer<uint4> gTetrahedra;
  53. Buffer<float4> gTetFaces;
  54. TextureCube gSkyIrradianceTex;
  55. Texture2D gAmbientOcclusionTex;
  56. SamplerState gLinearSamp;
  57. cbuffer Params
  58. {
  59. float gSkyBrightness;
  60. uint gNumTetrahedra;
  61. }
  62. Tetrahedron getTetrahedron(uint idx)
  63. {
  64. Tetrahedron output;
  65. uint4 data[6];
  66. [unroll]
  67. for(int i = 0; i < 6; i++)
  68. data[i] = gTetrahedra.Load(idx * 6 + i);
  69. output.indices = data[0];
  70. output.offsets[0] = data[1].xy;
  71. output.offsets[1] = data[1].zw;
  72. output.offsets[2] = data[2].xy;
  73. output.offsets[3] = data[2].zw;
  74. output.transform = float3x4(asfloat(data[3]), asfloat(data[4]), asfloat(data[5]));
  75. return output;
  76. }
  77. TetrahedronFace getTetrahedronFace(uint idx)
  78. {
  79. TetrahedronFace output;
  80. float4 data[7];
  81. [unroll]
  82. for(int i = 0; i < 7; i++)
  83. data[i] = gTetFaces.Load(idx * 7 + i);
  84. [unroll]
  85. for(int i = 0; i < 3; i++)
  86. {
  87. output.corners[i] = data[i];
  88. output.normals[i] = data[3 + i];
  89. output.padding[i] = 0;
  90. }
  91. output.isQuadratic = asuint(data[6].x);
  92. return output;
  93. }
  94. float3 getSkyIndirectDiffuse(float3 dir)
  95. {
  96. return gSkyIrradianceTex.SampleLevel(gLinearSamp, dir, 0).rgb * gSkyBrightness;
  97. }
  98. float evaluateLambert(SHVector coeffs)
  99. {
  100. // Multiply irradiance SH coefficients by cosine lobe (Lambert diffuse) and evaluate resulting SH
  101. // See: http://cseweb.ucsd.edu/~ravir/papers/invlamb/josa.pdf for derivation of the
  102. // cosine lobe factors
  103. float output = 0.0f;
  104. // Band 0 (factor 1.0)
  105. output += coeffs.v[0];
  106. // Band 1 (factor 2/3)
  107. float f = (2.0f/3.0f);
  108. for(int i = 1; i < 4; i++)
  109. output += coeffs.v[i] * f;
  110. // Band 2 (factor 1/4)
  111. f = (1.0f/4.0f);
  112. for(int i = 4; i < 9; i++)
  113. output += coeffs.v[i] * f;
  114. return output;
  115. }
  116. float solveQuadratic(float A, float B, float C)
  117. {
  118. const float EPSILON = 0.00001f;
  119. if (abs(A) > EPSILON)
  120. {
  121. float p = B / (2 * A);
  122. float q = C / A;
  123. float D = p * p - q;
  124. return sqrt(D) - p;
  125. }
  126. else
  127. {
  128. if(abs(B) > EPSILON)
  129. return -C / B;
  130. return 0.0f;
  131. }
  132. }
  133. float solveCubic(float A, float B, float C)
  134. {
  135. const float EPSILON = 0.00001f;
  136. const float THIRD = 1.0f / 3.0f;
  137. float sqA = A * A;
  138. float p = THIRD * (-THIRD * sqA + B);
  139. float q = (0.5f) * ((2.0f / 27.0f) * A * sqA - THIRD * A * B + C);
  140. float cbp = p * p * p;
  141. float D = q * q + cbp;
  142. float t;
  143. if(D < 0.0f)
  144. {
  145. float phi = THIRD * acos(-q / sqrt(-cbp));
  146. t = (2 * sqrt(-p)) * cos(phi);
  147. }
  148. else
  149. {
  150. float sqrtD = sqrt(D);
  151. float u = pow(sqrtD + abs(q), 1.0f / 3.0f);
  152. if (q > 0.0f)
  153. t = -u + p / u;
  154. else
  155. t = u - p / u;
  156. }
  157. return t - THIRD * A;
  158. }
  159. float3 calcTriBarycentric(float3 p, float3 a, float3 b, float3 c)
  160. {
  161. float3 v0 = b - a;
  162. float3 v1 = c - a;
  163. float3 v2 = p - a;
  164. float d00 = dot(v0, v0);
  165. float d01 = dot(v0, v1);
  166. float d11 = dot(v1, v1);
  167. float d20 = dot(v2, v0);
  168. float d21 = dot(v2, v1);
  169. float denom = d00 * d11 - d01 * d01;
  170. float3 coords;
  171. coords.x = (d11 * d20 - d01 * d21) / denom;
  172. coords.y = (d00 * d21 - d01 * d20) / denom;
  173. coords.z = 1.0f - coords.x - coords.y;
  174. return coords;
  175. }
  176. float4 fsmain(VStoFS input
  177. #if MSAA_COUNT > 1 && !MSAA_RESOLVE_0TH
  178. , uint sampleIdx : SV_SampleIndex
  179. #endif
  180. ) : SV_Target0
  181. {
  182. uint2 pixelPos = trunc(input.uv0);
  183. SurfaceData surfaceData;
  184. #if MSAA_COUNT > 1
  185. #if MSAA_RESOLVE_0TH
  186. surfaceData = getGBufferData(pixelPos, 0);
  187. #else
  188. surfaceData = getGBufferData(pixelPos, sampleIdx);
  189. #endif
  190. #else
  191. surfaceData = getGBufferData(pixelPos);
  192. #endif
  193. float3 irradiance = 0;
  194. #if SKY_ONLY
  195. irradiance = gSkyIrradianceTex.SampleLevel(gLinearSamp, surfaceData.worldNormal, 0).rgb * gSkyBrightness;
  196. #else
  197. uint volumeIdx;
  198. #if MSAA_COUNT > 1
  199. #if MSAA_RESOLVE_0TH
  200. volumeIdx = gInputTex.Load(uint3(pixelPos, 0), 0).x;
  201. #else
  202. volumeIdx = gInputTex.Load(uint3(pixelPos, 0), sampleIdx).x;
  203. #endif
  204. #else
  205. volumeIdx = gInputTex.Load(uint3(pixelPos, 0)).x;
  206. #endif
  207. if(volumeIdx == 0xFFFF) // Using 16-bit texture, so need to compare like this
  208. irradiance = gSkyIrradianceTex.SampleLevel(gLinearSamp, surfaceData.worldNormal, 0).rgb * gSkyBrightness;
  209. else
  210. {
  211. Tetrahedron volume = getTetrahedron(volumeIdx);
  212. float3 P = NDCToWorld(input.screenPos, surfaceData.depth);
  213. float4 coords;
  214. [branch]
  215. if(volumeIdx >= gNumTetrahedra)
  216. {
  217. uint faceIdx = volumeIdx - gNumTetrahedra;
  218. TetrahedronFace face = getTetrahedronFace(faceIdx);
  219. float3 factors = mul(volume.transform, float4(P, 1.0f));
  220. float A = factors.x;
  221. float B = factors.y;
  222. float C = factors.z;
  223. float t;
  224. if(face.isQuadratic > 0)
  225. t = solveQuadratic(A, B, C);
  226. else
  227. t = solveCubic(A, B, C);
  228. float3 triA = face.corners[0].xyz + t * face.normals[0].xyz;
  229. float3 triB = face.corners[1].xyz + t * face.normals[1].xyz;
  230. float3 triC = face.corners[2].xyz + t * face.normals[2].xyz;
  231. float3 bary = calcTriBarycentric(P, triA, triB, triC);
  232. coords.x = bary.z;
  233. coords.yz = bary.xy;
  234. coords.w = 0.0f;
  235. }
  236. else
  237. {
  238. float3 factors = mul(volume.transform, float4(P, 1.0f));
  239. coords = float4(factors, 1.0f - factors.x - factors.y - factors.z);
  240. }
  241. SHVectorRGB shCoeffs;
  242. SHZero(shCoeffs);
  243. for(uint i = 0; i < 4; ++i)
  244. {
  245. if(coords[i] > 0.0f)
  246. {
  247. SHVectorRGB coeff = SHLoad(gSHCoeffs, volume.offsets[i]);
  248. SHMultiplyAdd(shCoeffs, coeff, coords[i]);
  249. }
  250. }
  251. SHVector shBasis = SHBasis(surfaceData.worldNormal);
  252. SHMultiply(shCoeffs.R, shBasis);
  253. SHMultiply(shCoeffs.G, shBasis);
  254. SHMultiply(shCoeffs.B, shBasis);
  255. irradiance.r = evaluateLambert(shCoeffs.R);
  256. irradiance.g = evaluateLambert(shCoeffs.G);
  257. irradiance.b = evaluateLambert(shCoeffs.B);
  258. }
  259. #endif // SKY_ONLY
  260. float2 uv = NDCToUV(input.screenPos);
  261. float ao = gAmbientOcclusionTex.Sample(gLinearSamp, uv);
  262. float3 diffuseColor = lerp(surfaceData.albedo.rgb, float3(0.0f, 0.0f, 0.0f), surfaceData.metalness);
  263. return float4(irradiance * diffuseColor * ao, 1.0f);
  264. }
  265. };
  266. };