light-frag-params.glsl.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. *
  6. * adapted from three.js (https://github.com/mrdoob/three.js/)
  7. * which under the MIT License, Copyright © 2010-2021 three.js authors
  8. */
  9. export const light_frag_params = `
  10. uniform vec3 uLightDirection[dLightCount];
  11. uniform vec3 uLightColor[dLightCount];
  12. uniform vec3 uAmbientColor;
  13. uniform float uReflectivity;
  14. uniform float uMetalness;
  15. uniform float uRoughness;
  16. struct PhysicalMaterial {
  17. vec3 diffuseColor;
  18. float roughness;
  19. vec3 specularColor;
  20. float specularF90;
  21. };
  22. struct IncidentLight {
  23. vec3 color;
  24. vec3 direction;
  25. };
  26. struct ReflectedLight {
  27. vec3 directDiffuse;
  28. vec3 directSpecular;
  29. vec3 indirectDiffuse;
  30. vec3 indirectSpecular;
  31. };
  32. struct GeometricContext {
  33. vec3 position;
  34. vec3 normal;
  35. vec3 viewDir;
  36. };
  37. vec3 BRDF_Lambert(const in vec3 diffuseColor) {
  38. return RECIPROCAL_PI * diffuseColor;
  39. }
  40. vec3 F_Schlick(const in vec3 f0, const in float f90, const in float dotVH) {
  41. // Original approximation by Christophe Schlick '94
  42. // float fresnel = pow( 1.0 - dotVH, 5.0 );
  43. // Optimized variant (presented by Epic at SIGGRAPH '13)
  44. // https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
  45. float fresnel = exp2((-5.55473 * dotVH - 6.98316) * dotVH);
  46. return f0 * (1.0 - fresnel) + (f90 * fresnel);
  47. }
  48. // Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
  49. // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  50. float V_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) {
  51. float a2 = pow2(alpha);
  52. float gv = dotNL * sqrt(a2 + (1.0 - a2) * pow2(dotNV));
  53. float gl = dotNV * sqrt(a2 + (1.0 - a2) * pow2(dotNL));
  54. return 0.5 / max(gv + gl, EPSILON);
  55. }
  56. // Microfacet Models for Refraction through Rough Surfaces - equation (33)
  57. // http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
  58. // alpha is "roughness squared" in Disney’s reparameterization
  59. float D_GGX(const in float alpha, const in float dotNH) {
  60. float a2 = pow2(alpha);
  61. float denom = pow2(dotNH) * (a2 - 1.0) + 1.0; // avoid alpha = 0 with dotNH = 1
  62. return RECIPROCAL_PI * a2 / pow2(denom);
  63. }
  64. // GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
  65. vec3 BRDF_GGX(const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness) {
  66. float alpha = pow2(roughness); // UE4's roughness
  67. vec3 halfDir = normalize( lightDir + viewDir);
  68. float dotNL = saturate(dot(normal, lightDir));
  69. float dotNV = saturate(dot(normal, viewDir));
  70. float dotNH = saturate(dot(normal, halfDir));
  71. float dotVH = saturate(dot(viewDir, halfDir));
  72. vec3 F = F_Schlick(f0, f90, dotVH);
  73. float V = V_GGX_SmithCorrelated(alpha, dotNL, dotNV);
  74. float D = D_GGX(alpha, dotNH);
  75. return F * (V * D);
  76. }
  77. // Analytical approximation of the DFG LUT, one half of the
  78. // split-sum approximation used in indirect specular lighting.
  79. // via 'environmentBRDF' from "Physically Based Shading on Mobile"
  80. // https://www.unrealengine.com/blog/physically-based-shading-on-mobile
  81. vec2 DFGApprox(const in vec3 normal, const in vec3 viewDir, const in float roughness) {
  82. float dotNV = saturate(dot(normal, viewDir));
  83. const vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022);
  84. const vec4 c1 = vec4(1, 0.0425, 1.04, -0.04);
  85. vec4 r = roughness * c0 + c1;
  86. float a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y;
  87. vec2 fab = vec2(-1.04, 1.04) * a004 + r.zw;
  88. return fab;
  89. }
  90. // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
  91. // Approximates multiscattering in order to preserve energy.
  92. // http://www.jcgt.org/published/0008/01/03/
  93. void computeMultiscattering(const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter) {
  94. vec2 fab = DFGApprox(normal, viewDir, roughness);
  95. vec3 FssEss = specularColor * fab.x + specularF90 * fab.y;
  96. float Ess = fab.x + fab.y;
  97. float Ems = 1.0 - Ess;
  98. vec3 Favg = specularColor + (1.0 - specularColor) * 0.047619; // 1/21
  99. vec3 Fms = FssEss * Favg / (1.0 - Ems * Favg);
  100. singleScatter += FssEss;
  101. multiScatter += Fms * Ems;
  102. }
  103. void RE_Direct_Physical(const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {
  104. float dotNL = saturate(dot(geometry.normal, directLight.direction));
  105. vec3 irradiance = dotNL * directLight.color;
  106. reflectedLight.directSpecular += irradiance * BRDF_GGX(directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness);
  107. reflectedLight.directDiffuse += irradiance * BRDF_Lambert(material.diffuseColor);
  108. }
  109. void RE_IndirectDiffuse_Physical(const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {
  110. reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert(material.diffuseColor);
  111. }
  112. void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {
  113. // Both indirect specular and indirect diffuse light accumulate here
  114. vec3 singleScattering = vec3(0.0);
  115. vec3 multiScattering = vec3(0.0);
  116. vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;
  117. computeMultiscattering(geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering);
  118. vec3 diffuse = material.diffuseColor * (1.0 - ( singleScattering + multiScattering));
  119. reflectedLight.indirectSpecular += radiance * singleScattering;
  120. reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;
  121. reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;
  122. }
  123. `;