ReflProbeAccumulator.bslinc 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //
  2. // Contains helper mixin used for initializing different forms of refl. probe accumulation. Can be removed
  3. // when template/specialization support for mixins is added to BSL.
  4. //
  5. #ifdef USE_UNIFORM_BUFFER
  6. mixin ReflProbeAccumulatorDirect
  7. #else
  8. mixin ReflProbeAccumulatorIndexed
  9. #endif
  10. {
  11. code
  12. {
  13. #ifdef USE_UNIFORM_BUFFER
  14. #define MAX_PROBES 8
  15. [internal]
  16. cbuffer ReflProbes
  17. {
  18. ReflProbeData gReflectionProbes[MAX_PROBES];
  19. }
  20. #else
  21. #define MAX_PROBES 512 // Arbitrary limit, increase if needed
  22. #ifdef USE_COMPUTE_INDICES
  23. groupshared uint gReflectionProbeIndices[MAX_PROBES];
  24. StructuredBuffer<ReflProbeData> gReflectionProbes;
  25. #endif
  26. #ifdef USE_LIGHT_GRID_INDICES
  27. Buffer<uint> gReflectionProbeIndices;
  28. StructuredBuffer<ReflProbeData> gReflectionProbes;
  29. #endif
  30. #endif
  31. float3 gatherReflectionRadiance(float3 worldPos, float3 dir, float roughness, float alpha, float3 specularColor, uint probeOffset, uint numProbes)
  32. {
  33. if(gUseReflectionMaps == 0)
  34. return specularColor;
  35. float mipLevel = mapRoughnessToMipLevel(roughness, gReflCubemapNumMips);
  36. float3 output = 0;
  37. [loop]
  38. for(uint i = 0; i < numProbes; i++)
  39. {
  40. if(alpha < 0.001f)
  41. break;
  42. #ifdef USE_UNIFORM_BUFFER
  43. uint probeIdx = probeOffset + i;
  44. #else
  45. uint probeIdx = gReflectionProbeIndices[probeOffset + i];
  46. #endif
  47. ReflProbeData probeData = gReflectionProbes[probeIdx];
  48. float4 probeValue = evaluateProbe(worldPos, dir, mipLevel, probeData);
  49. output += probeValue.rgb * alpha;
  50. alpha *= probeValue.w;
  51. }
  52. if(gSkyCubemapAvailable > 0)
  53. {
  54. float skyMipLevel = mapRoughnessToMipLevel(roughness, gSkyCubemapNumMips);
  55. float4 skySample = gSkyReflectionTex.SampleLevel(gSkyReflectionSamp, dir, skyMipLevel) * gSkyBrightness;
  56. output += skySample.rgb * alpha;
  57. }
  58. return output;
  59. }
  60. float3 getImageBasedSpecular(float3 worldPos, float3 V, float3 R, SurfaceData surfaceData, float ao, float4 ssr,
  61. uint probeOffset, uint numProbes)
  62. {
  63. // See C++ code for generation of gPreintegratedEnvBRDF to see why this code works as is
  64. float3 N = surfaceData.worldNormal.xyz;
  65. float NoV = saturate(dot(N, V));
  66. // Note: Using a fixed F0 value of 0.04 (plastic) for dielectrics, and using albedo as specular for conductors.
  67. // For more customizability allow the user to provide separate albedo/specular colors for both types.
  68. float3 specularColor = lerp(float3(0.04f, 0.04f, 0.04f), surfaceData.albedo.rgb, surfaceData.metalness);
  69. // Get SSR
  70. float3 radiance = ssr.rgb;
  71. float alpha = 1.0f - ssr.a; // Determines how much to blend in reflection probes & skybox
  72. // Generate an approximate spec. occlusion value from AO. This doesn't need to be applied to SSR since it accounts
  73. // for occlusion by tracing rays.
  74. float specOcclusion = getSpecularOcclusion(NoV, surfaceData.roughness * surfaceData.roughness, ao);
  75. alpha *= specOcclusion;
  76. // Get radiance from probes and skybox
  77. radiance += gatherReflectionRadiance(worldPos, R, surfaceData.roughness, alpha, specularColor, probeOffset, numProbes);
  78. float2 envBRDF = gPreintegratedEnvBRDF.SampleLevel(gPreintegratedEnvBRDFSamp, float2(NoV, surfaceData.roughness), 0).rg;
  79. return radiance * (specularColor * envBRDF.x + envBRDF.y);
  80. }
  81. };
  82. };