IBL.hlsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #ifdef COMPILEPS
  2. // float3 ImportanceSampleSimple(in float2 Xi, in float roughness, in float3 T, in float3 B, in float3 N)
  3. // {
  4. // const float a = roughness * roughness;
  5. // const float3x3 tbn = float3x3(T, B, N);
  6. // #ifdef IBLFAST
  7. // const float blurFactor = 0.0;
  8. // #else
  9. // const float blurFactor = 5.0;
  10. // #endif
  11. // const float3 Xi3 = lerp(float3(0,0,1), normalize(float3(Xi.xy * blurFactor % 1.0 , 1.0)), a);
  12. // const float3 XiWS = mul(Xi3, tbn);
  13. // return normalize(N + XiWS);
  14. // }
  15. // // Karis '13
  16. // float3 ImportanceSampleGGX(in float2 Xi, in float roughness, in float3 T, in float3 B, in float3 N)
  17. // {
  18. // float a = roughness * roughness;
  19. // float Phi = 2.0 * M_PI * Xi.x;
  20. // float CosTheta = (sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)));
  21. // float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
  22. // float3 H = 0;
  23. // H.x = SinTheta * cos(Phi);
  24. // H.y = SinTheta * sin(Phi);
  25. // H.z = CosTheta;
  26. // float3 UpVector = abs(N.z) < 0.999 ? float3(0, 0, 1) : float3(1, 0, 0);
  27. // float3 TangentX = normalize(cross(UpVector, N));
  28. // float3 TangentY = cross(N, TangentX);
  29. // // Tangent to world space
  30. // return TangentX * H.x + TangentY * H.y + N * H.z;
  31. // }
  32. // #ifdef IBLFAST
  33. // #define IMPORTANCE_SAMPLES 1
  34. // #else
  35. // #define IMPORTANCE_SAMPLES 16
  36. // #endif
  37. // #define IMPORTANCE_KERNEL_SIZE 16
  38. // static const float2 IMPORTANCE_KERNEL[IMPORTANCE_KERNEL_SIZE] =
  39. // {
  40. // float2(-0.0780436, 0.0558389),
  41. // float2(0.034318, -0.0635879),
  42. // float2(0.00230821, 0.0807279),
  43. // float2(0.0124638, 0.117585),
  44. // float2(0.093943, -0.0944602),
  45. // float2(0.139348, -0.109816),
  46. // float2(-0.181872, -0.129649),
  47. // float2(0.240066, -0.0494057),
  48. // float2(0.115965, -0.0374714),
  49. // float2(-0.294819, -0.100726),
  50. // float2(-0.149652, 0.37459),
  51. // float2(0.261695, -0.292813),
  52. // float2(-0.37944, -0.425145),
  53. // float2(0.628994, -0.189387),
  54. // float2(-0.331257, -0.646864),
  55. // float2(-0.467004, 0.439687),
  56. // };
  57. // float GetMipFromRougness(float roughness)
  58. // {
  59. // const float smoothness = 1.0 - roughness;
  60. // return (1.0 - smoothness * smoothness) * 10.0;
  61. // }
  62. // /// Perform importance sampling
  63. // /// reflectVec: calculated vector of reflection
  64. // /// wsNormal: world-space normal of the surface
  65. // /// toCamera: direction from the pixel to the camera
  66. // /// specular: specular color
  67. // /// roughness: surface roughness
  68. // /// reflectionCubeColor: output color for diffuse
  69. // // Implementation based on Epics 2013 course notes
  70. // float3 ImportanceSampling(in float3 reflectVec, in float3 tangent, in float3 bitangent, in float3 wsNormal, in float3 toCamera, in float3 diffColor, in float3 specColor, in float roughness, inout float3 reflectionCubeColor)
  71. // {
  72. // reflectionCubeColor = 1.0;
  73. // const float3 reflectSpec = normalize(GetSpecularDominantDir(wsNormal, reflectVec, roughness));
  74. // const float3 V = normalize(-toCamera);
  75. // const float3 N = normalize(wsNormal);
  76. // const float ndv = saturate(abs(dot(N, V)));
  77. // const float specMipLevel = GetMipFromRougness(roughness);
  78. // float3 accumulatedColor = float3(0,0,0);
  79. // for (int i = 0; i < IMPORTANCE_SAMPLES; ++i)
  80. // {
  81. // float3 kd = 1.0;
  82. // float3 diffuseFactor = 0.0;
  83. // float3 specularFactor = 0.0;
  84. // {
  85. // // Diffuse IBL
  86. // const float rough = 1.0;
  87. // const float mipLevel = 9.0;
  88. // const float3 H = ImportanceSampleSimple(IMPORTANCE_KERNEL[i], rough, tangent, bitangent, N);
  89. // const float3 L = 2.0 * dot( V, H ) * H - V;
  90. // const float vdh = saturate(abs(dot(V, H)));
  91. // const float ndh = saturate(abs(dot(N, H)));
  92. // const float ndl = saturate(abs(dot(N, L)));
  93. // const float3 sampledColor = SampleCubeLOD(ZoneCubeMap, float4(L, mipLevel));
  94. // const float3 diffuseTerm = Diffuse(diffColor, rough, ndv, ndl, vdh);
  95. // const float3 lightTerm = sampledColor;
  96. // diffuseFactor = lightTerm * diffuseTerm;
  97. // }
  98. // {
  99. // // Specular IBL
  100. // const float rough = roughness;
  101. // const float mipLevel = specMipLevel;
  102. // const float3 H = ImportanceSampleSimple(IMPORTANCE_KERNEL[i], rough, tangent, bitangent, N);
  103. // const float3 L = 2.0 * dot( V, H ) * H - V;
  104. // const float3 sampledColor = SampleCubeLOD(ZoneCubeMap, float4(L, mipLevel));
  105. // const float vdh = saturate(abs(dot(V, H)));
  106. // const float ndh = saturate(abs(dot(N, H)));
  107. // const float ndl = saturate(abs(dot(N, L)));
  108. // const float3 fresnelTerm = Fresnel(specColor, vdh);
  109. // const float distTerm = 1.0;//Distribution(ndh_, roughness);
  110. // const float visTerm = Visibility(ndl, ndv, rough);
  111. // const float3 lightTerm = sampledColor * ndl;
  112. // const float pdf = ndl > 0.05 ? ImportanceSamplePDF(distTerm, ndh, vdh) : 4.0; // reduce artifacts at extreme grazing angles
  113. // const float3 specularTerm = SpecularBRDF(distTerm, fresnelTerm, visTerm, ndl, ndv);
  114. // // Energy conservation:
  115. // // Specular conservation:
  116. // specularFactor = lightTerm * specularTerm / pdf;
  117. // specularFactor = max(saturate(normalize(specularFactor) * (length(sampledColor * specColor))), specularFactor);
  118. // // Diffuse conservation:
  119. // kd = 1.0 - specularFactor;
  120. // }
  121. // accumulatedColor += specularFactor + diffuseFactor * kd;
  122. // }
  123. // return (accumulatedColor / IMPORTANCE_SAMPLES);
  124. // }
  125. // float3 ImportanceSamplingSimple(in float3 reflectVec, in float3 tangent, in float3 bitangent, in float3 wsNormal, in float3 toCamera, in float3 diffColor, in float3 specColor, in float roughness, inout float3 reflectionCubeColor)
  126. // {
  127. // reflectionCubeColor = 1.0;
  128. // reflectVec = normalize(GetSpecularDominantDir(wsNormal, reflectVec, roughness));
  129. // const float3 Hn = normalize(-toCamera + wsNormal);
  130. // const float ndv = saturate(dot(-toCamera, wsNormal));
  131. // const float vdh = saturate(dot(-toCamera, Hn));
  132. // const float ndh = saturate(dot(wsNormal, Hn));
  133. // float3 accumulatedColor = float3(0,0,0);
  134. // for (int i = 0; i < IMPORTANCE_SAMPLES; ++i)
  135. // {
  136. // float3 kd = 1.0;
  137. // float3 diffuseFactor = 0.0;
  138. // float3 specularFactor = 0.0;
  139. // {
  140. // // Diffuse IBL
  141. // const float rough = 1.0;
  142. // const float mipLevel = 9.0;
  143. // const float3 perturb = ImportanceSampleGGX(IMPORTANCE_KERNEL[i].xy, rough, tangent, bitangent, wsNormal);
  144. // const float3 sampleVec = wsNormal + perturb; //perturb by the sample vector
  145. // const float3 sampledColor = SampleCubeLOD(ZoneCubeMap, float4(sampleVec, mipLevel));
  146. // const float ndl = saturate(dot(sampleVec, wsNormal));
  147. // const float3 diffuseTerm = Diffuse(diffColor, rough, ndv, ndl, vdh);
  148. // const float3 lightTerm = sampledColor;
  149. // diffuseFactor = lightTerm * diffuseTerm;
  150. // }
  151. // {
  152. // // Specular IBL
  153. // const float rough = roughness;
  154. // const float mipLevel = GetMipFromRougness(rough);
  155. // const float3 perturb = ImportanceSampleGGX(IMPORTANCE_KERNEL[i].xy, rough, tangent, bitangent, reflectVec);
  156. // const float3 sampleVec = reflectVec + perturb; //perturb by the sample vector
  157. // const float3 sampledColor = SampleCubeLOD(ZoneCubeMap, float4(sampleVec, mipLevel));
  158. // const float ndl = saturate(dot(sampleVec, wsNormal));
  159. // const float3 fresnelTerm = SchlickFresnel(specColor, ndh) ;
  160. // const float distTerm = 1.0; //Optimization, this term is mathematically cancelled out //Distribution(ndh, roughness);
  161. // const float visTerm = SmithGGXVisibility(ndl, ndv, rough);
  162. // const float3 lightTerm = sampledColor * ndl;
  163. // const float pdf = 1.0;//ImportanceSamplePDF(distTerm, ndh, vdh);
  164. // specularFactor = lightTerm * SpecularBRDF(distTerm, fresnelTerm, visTerm, ndl, ndv) / pdf;
  165. // specularFactor *= pdf * ndv * (4.0 * ndl * ndv); // hacks
  166. // kd = (1.0 - saturate(specularFactor)); //energy conservation
  167. // }
  168. // accumulatedColor += specularFactor + diffuseFactor * kd;
  169. // }
  170. // return accumulatedColor / IMPORTANCE_SAMPLES;
  171. // }
  172. /// Determine reflection vector based on surface roughness, rougher uses closer to the normal and smoother uses closer to the reflection vector
  173. /// normal: surface normal
  174. /// reflection: vector of reflection off of the surface
  175. /// roughness: surface roughness
  176. // float3 GetSpecularDominantDir(float3 normal, float3 reflection, float roughness)
  177. // {
  178. // const float smoothness = 1.0 - roughness;
  179. // const float lerpFactor = smoothness * (sqrt(smoothness) + roughness);
  180. // return lerp(normal, reflection, lerpFactor);
  181. // }
  182. float GetMipFromRoughness(float roughness)
  183. {
  184. return (roughness * 12.0 - pow(roughness, 6.0) * 1.5);
  185. }
  186. float3 EnvBRDFApprox (float3 specColor, float roughness, float ndv)
  187. {
  188. const float4 c0 = float4(-1, -0.0275, -0.572, 0.022 );
  189. const float4 c1 = float4(1, 0.0425, 1.0, -0.04 );
  190. float4 r = roughness * c0 + c1;
  191. float a004 = min( r.x * r.x, exp2( -9.28 * ndv ) ) * r.x + r.y;
  192. float2 AB = float2( -1.04, 1.04 ) * a004 + r.zw;
  193. return specColor * AB.x + AB.y;
  194. }
  195. float3 FixCubeLookup(float3 v)
  196. {
  197. float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
  198. float scale = (1024 - 1) / 1024;
  199. if (abs(v.x) != M) v.x += scale;
  200. if (abs(v.y) != M) v.y += scale;
  201. if (abs(v.z) != M) v.z += scale;
  202. return v;
  203. }
  204. /// Calculate IBL contributation
  205. /// reflectVec: reflection vector for cube sampling
  206. /// wsNormal: surface normal in word space
  207. /// toCamera: normalized direction from surface point to camera
  208. /// roughness: surface roughness
  209. /// ambientOcclusion: ambient occlusion
  210. float3 ImageBasedLighting(in float3 reflectVec, in float3 tangent, in float3 bitangent, in float3 wsNormal, in float3 toCamera, in float3 diffColor, in float3 specColor, in float roughness, inout float3 reflectionCubeColor)
  211. {
  212. roughness = max(roughness, 0.08);
  213. reflectVec = GetSpecularDominantDir(wsNormal, reflectVec, roughness);
  214. const float ndv = saturate(dot(-toCamera, wsNormal));
  215. /// Test: Parallax correction, currently not working
  216. // float3 intersectMax = (cZoneMax - toCamera) / reflectVec;
  217. // float3 intersectMin = (cZoneMin - toCamera) / reflectVec;
  218. // float3 furthestPlane = max(intersectMax, intersectMin);
  219. // float planeDistance = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
  220. // // Get the intersection position
  221. // float3 intersectionPos = toCamera + reflectVec * planeDistance;
  222. // // Get corrected reflection
  223. // reflectVec = intersectionPos - ((cZoneMin + cZoneMax )/ 2);
  224. const float mipSelect = GetMipFromRoughness(roughness);
  225. float3 cube = SampleCubeLOD(ZoneCubeMap, float4(FixCubeLookup(reflectVec), mipSelect)).rgb;
  226. float3 cubeD = SampleCubeLOD(ZoneCubeMap, float4(FixCubeLookup(wsNormal), 9.0)).rgb;
  227. // Fake the HDR texture
  228. float brightness = clamp(cAmbientColor.a, 0.0, 1.0);
  229. float darknessCutoff = clamp((cAmbientColor.a - 1.0) * 0.1, 0.0, 0.25);
  230. const float hdrMaxBrightness = 5.0;
  231. float3 hdrCube = pow(cube + darknessCutoff, max(1.0, cAmbientColor.a));
  232. hdrCube += max(0.0, hdrCube - 1.0) * hdrMaxBrightness;
  233. float3 hdrCubeD = pow(cubeD + darknessCutoff, max(1.0, cAmbientColor.a));
  234. hdrCubeD += max(0.0, hdrCubeD - 1.0) * hdrMaxBrightness;
  235. const float3 environmentSpecular = EnvBRDFApprox(specColor, roughness, ndv);
  236. const float3 environmentDiffuse = EnvBRDFApprox(diffColor, 1.0, ndv);
  237. return (hdrCube * environmentSpecular + hdrCubeD * environmentDiffuse) * brightness;
  238. //return ImportanceSampling(reflectVec, tangent, bitangent, wsNormal, toCamera, diffColor, specColor, roughness, reflectionCubeColor);
  239. }
  240. #endif