IBL.glsl 13 KB

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