ReflectionCubeImportanceSample.bsl 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #include "$ENGINE$\PPBase.bslinc"
  2. #include "$ENGINE$\ReflectionCubemapCommon.bslinc"
  3. #include "$ENGINE$\ImportanceSampling.bslinc"
  4. technique ReflectionCubeImportanceSample
  5. {
  6. mixin PPBase;
  7. mixin ReflectionCubemapCommon;
  8. mixin ImportanceSampling;
  9. code
  10. {
  11. cbuffer Input
  12. {
  13. int gCubeFace;
  14. int gMipLevel;
  15. int gNumMips;
  16. float gPrecomputedMipFactor;
  17. }
  18. SamplerState gInputSamp;
  19. TextureCube gInputTex;
  20. float4 fsmain(VStoFS input) : SV_Target0
  21. {
  22. float2 scaledUV = input.uv0 * 2.0f - 1.0f;
  23. float3 N = getDirFromCubeFace(gCubeFace, scaledUV);
  24. N = normalize(N);
  25. // Determine which mip level to sample from depending on PDF and cube -> sphere mapping distortion
  26. float distortion = rcp(pow(N.x * N.x + N.y * N.y + N.z * N.z, 3.0f/2.0f));
  27. float roughness = mapMipLevelToRoughness(gMipLevel, gNumMips);
  28. float roughness2 = roughness * roughness;
  29. float roughness4 = roughness2 * roughness2;
  30. float4 sum = 0;
  31. for(uint i = 0; i < NUM_SAMPLES; i++)
  32. {
  33. float2 random = hammersleySequence(i, NUM_SAMPLES);
  34. float2 sphericalH = importanceSampleGGX(random, roughness4);
  35. float cosTheta = sphericalH.x;
  36. float phi = sphericalH.y;
  37. float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
  38. float3 H = sphericalToCartesian(cosTheta, sinTheta, phi);
  39. float PDF = pdfGGX(cosTheta, sinTheta, roughness4);
  40. // Transform H to world space
  41. float3 up = abs(H.z) < 0.999 ? float3(0, 0, 1) : float3(1, 0, 0);
  42. float3 tangentX = normalize(cross(up, N));
  43. float3 tangentY = cross(N, tangentX);
  44. H = tangentX * H.x + tangentY * H.y + N * H.z;
  45. // Calculating mip level from distortion and pdf and described by http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
  46. int mipLevel = max(gPrecomputedMipFactor - 0.5f * log2(PDF * distortion), 0);
  47. // Note: Adding +1 bias as it looks better
  48. mipLevel++;
  49. // We need a light direction to properly evaluate the NoL term of the evaluation integral
  50. // Li(u) * brdf(u, v) * (u.n) / pdf(u, v)
  51. // which we don't have, so we assume a viewing direction is equal to normal and calculate lighting dir from it and half-vector
  52. float3 L = 2 * dot(N, H) * H - N;
  53. float NoL = saturate(dot(N, L));
  54. // sum += radiance * GGX(h, roughness) * NoL / PDF. In GGX/PDF most factors cancel out and we're left with 1/cos (sine factor of the PDF only needed for the integral (I think), so we don't include it)
  55. if(NoL > 0)
  56. sum += gInputTex.SampleLevel(gInputSamp, H, mipLevel) * NoL / cosTheta;
  57. }
  58. return sum / NUM_SAMPLES;
  59. }
  60. };
  61. };