PBREnvBaking.fs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap
  2. #if (__VERSION__ >= 120)
  3. uniform int uSamplesNum; //!< number of samples in Monte-Carlo integration
  4. #else
  5. const int uSamplesNum = 256;
  6. #endif
  7. uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)
  8. #ifdef THE_TO_BAKE_DIFFUSE
  9. uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap
  10. uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap
  11. #endif
  12. #ifdef THE_TO_BAKE_SPECULAR
  13. uniform int uCurrentLevel; //!< current level of specular IBL map (ignored in case of diffuse map's processing)
  14. uniform float uEnvSolidAngleSource; //!< source solid angle sample computed from one edge's size of source environment map's zero mipmap level
  15. #endif
  16. //! Returns coordinates of point theNumber from Hammersley point set having size theSize.
  17. vec2 hammersley (in int theNumber,
  18. in int theSize)
  19. {
  20. int aDenominator = 2;
  21. int aNumber = theNumber;
  22. float aVanDerCorput = 0.0;
  23. for (int i = 0; i < 32; ++i)
  24. {
  25. if (aNumber > 0)
  26. {
  27. aVanDerCorput += mod(float(aNumber), 2.0) / float(aDenominator);
  28. aNumber /= 2;
  29. aDenominator *= 2;
  30. }
  31. }
  32. return vec2(float(theNumber) / float(theSize), aVanDerCorput);
  33. }
  34. //! This function does importance sampling on hemisphere surface using GGX normal distribution function
  35. //! in tangent space (positive z axis is surface normal direction).
  36. vec3 importanceSample (in vec2 theHammersleyPoint,
  37. in float theRoughness)
  38. {
  39. float aPhi = PI_2 * theHammersleyPoint.x;
  40. theRoughness *= theRoughness;
  41. theRoughness *= theRoughness;
  42. float aCosTheta = sqrt((1.0 - theHammersleyPoint.y) / (1.0 + (theRoughness - 1.0) * theHammersleyPoint.y));
  43. float aSinTheta = sqrt(1.0 - aCosTheta * aCosTheta);
  44. return vec3(aSinTheta * cos(aPhi),
  45. aSinTheta * sin(aPhi),
  46. aCosTheta);
  47. }
  48. //! This function uniformly generates samples on whole sphere.
  49. vec3 sphereUniformSample (in vec2 theHammersleyPoint)
  50. {
  51. float aPhi = PI_2 * theHammersleyPoint.x;
  52. float aCosTheta = 2.0 * theHammersleyPoint.y - 1.0;
  53. float aSinTheta = sqrt(1.0 - aCosTheta * aCosTheta);
  54. return vec3(aSinTheta * cos(aPhi),
  55. aSinTheta * sin(aPhi),
  56. aCosTheta);
  57. }
  58. //! Transforms resulted sampled direction from tangent space to world space considering the surface normal.
  59. vec3 fromTangentSpace (in vec3 theVector,
  60. in vec3 theNormal)
  61. {
  62. vec3 anUp = (abs(theNormal.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
  63. vec3 anX = normalize(cross(anUp, theNormal));
  64. vec3 anY = cross(theNormal, anX);
  65. return anX * theVector.x + anY * theVector.y + theNormal * theVector.z;
  66. }
  67. #ifdef THE_TO_BAKE_DIFFUSE
  68. #if (__VERSION__ >= 120)
  69. const float aSHBasisFuncCoeffs[9] = float[9]
  70. (
  71. 0.282095 * 0.282095,
  72. 0.488603 * 0.488603,
  73. 0.488603 * 0.488603,
  74. 0.488603 * 0.488603,
  75. 1.092548 * 1.092548,
  76. 1.092548 * 1.092548,
  77. 1.092548 * 1.092548,
  78. 0.315392 * 0.315392,
  79. 0.546274 * 0.546274
  80. );
  81. const float aSHCosCoeffs[9] = float[9]
  82. (
  83. 3.141593,
  84. 2.094395,
  85. 2.094395,
  86. 2.094395,
  87. 0.785398,
  88. 0.785398,
  89. 0.785398,
  90. 0.785398,
  91. 0.785398
  92. );
  93. #else
  94. uniform float aSHBasisFuncCoeffs[9];
  95. uniform float aSHCosCoeffs[9];
  96. #endif
  97. //! Bakes diffuse IBL map's spherical harmonics coefficients.
  98. vec3 bakeDiffuseSH()
  99. {
  100. int anId = int(gl_FragCoord.x);
  101. float aCoef;
  102. #if (__VERSION__ >= 120)
  103. aCoef = aSHCosCoeffs[anId] * aSHBasisFuncCoeffs[anId];
  104. #else
  105. if (anId == 0) { aCoef = aSHCosCoeffs[0] * aSHBasisFuncCoeffs[0]; }
  106. else if (anId == 1) { aCoef = aSHCosCoeffs[1] * aSHBasisFuncCoeffs[1]; }
  107. else if (anId == 2) { aCoef = aSHCosCoeffs[2] * aSHBasisFuncCoeffs[2]; }
  108. else if (anId == 3) { aCoef = aSHCosCoeffs[3] * aSHBasisFuncCoeffs[3]; }
  109. else if (anId == 4) { aCoef = aSHCosCoeffs[4] * aSHBasisFuncCoeffs[4]; }
  110. else if (anId == 5) { aCoef = aSHCosCoeffs[5] * aSHBasisFuncCoeffs[5]; }
  111. else if (anId == 6) { aCoef = aSHCosCoeffs[6] * aSHBasisFuncCoeffs[6]; }
  112. else if (anId == 7) { aCoef = aSHCosCoeffs[7] * aSHBasisFuncCoeffs[7]; }
  113. else { aCoef = aSHCosCoeffs[8] * aSHBasisFuncCoeffs[8]; }
  114. #endif
  115. vec3 aRes = vec3 (0.0);
  116. for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
  117. {
  118. vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum);
  119. vec3 aDir = sphereUniformSample (aHammersleyPoint);
  120. vec3 aVal = occTextureCube (uEnvMap, cubemapVectorTransform (aDir, uYCoeff, uZCoeff)).rgb;
  121. #if (__VERSION__ >= 120)
  122. float aFunc[9];
  123. aFunc[0] = 1.0;
  124. aFunc[1] = aDir.x;
  125. aFunc[2] = aDir.y;
  126. aFunc[3] = aDir.z;
  127. aFunc[4] = aDir.x * aDir.z;
  128. aFunc[5] = aDir.y * aDir.z;
  129. aFunc[6] = aDir.x * aDir.y;
  130. aFunc[7] = 3.0 * aDir.z * aDir.z - 1.0;
  131. aFunc[8] = aDir.x * aDir.x - aDir.y * aDir.y;
  132. aRes += aVal * aFunc[anId];
  133. #else
  134. if (anId == 0) { aRes += aVal * 1.0; }
  135. else if (anId == 1) { aRes += aVal * aDir.x; }
  136. else if (anId == 2) { aRes += aVal * aDir.y; }
  137. else if (anId == 3) { aRes += aVal * aDir.z; }
  138. else if (anId == 4) { aRes += aVal * (aDir.x * aDir.z); }
  139. else if (anId == 5) { aRes += aVal * (aDir.y * aDir.z); }
  140. else if (anId == 6) { aRes += aVal * (aDir.x * aDir.y); }
  141. else if (anId == 7) { aRes += aVal * (3.0 * aDir.z * aDir.z - 1.0); }
  142. else { aRes += aVal * (aDir.x * aDir.x - aDir.y * aDir.y); }
  143. #endif
  144. }
  145. return 4.0 * aRes * aCoef / float(uSamplesNum);
  146. }
  147. #endif
  148. #ifdef THE_TO_BAKE_SPECULAR
  149. //! Computes a single sample for specular IBL map.
  150. vec4 specularMapSample (in vec3 theNormal,
  151. in float theRoughness,
  152. in int theNumber,
  153. in int theSize)
  154. {
  155. vec2 aHammersleyPoint = hammersley (theNumber, theSize);
  156. vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));
  157. float aHdotV = aHalf.z;
  158. aHalf = fromTangentSpace (aHalf, theNormal);
  159. vec3 aLight = -reflect (theNormal, aHalf);
  160. float aNdotL = dot (aLight, theNormal);
  161. if (aNdotL > 0.0)
  162. {
  163. float aSolidAngleSample = 1.0 / (float(theSize) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);
  164. float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / uEnvSolidAngleSource);
  165. return vec4 (occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL, aNdotL);
  166. }
  167. return vec4 (0.0);
  168. }
  169. //! Bakes specular IBL map.
  170. vec3 bakeSpecularMap (in vec3 theNormal,
  171. in float theRoughness)
  172. {
  173. vec4 aResult = vec4(0.0);
  174. if (theRoughness == 0.0)
  175. {
  176. aResult = specularMapSample (theNormal, theRoughness, 0, 1);
  177. }
  178. else
  179. {
  180. for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
  181. {
  182. aResult += specularMapSample (theNormal, theRoughness, aSampleIter, uSamplesNum);
  183. }
  184. }
  185. return aResult.xyz / aResult.w;
  186. }
  187. #endif
  188. void main()
  189. {
  190. vec3 aViewDirection = normalize (ViewDirection);
  191. #ifdef THE_TO_BAKE_DIFFUSE
  192. vec4 aRes = vec4 (bakeDiffuseSH(), 1.0);
  193. #ifdef THE_TO_PACK_FLOAT
  194. int aCompIndex = int(gl_FragCoord.y);
  195. float aComp = aCompIndex == 0 ? aRes.x : (aCompIndex == 1 ? aRes.y : aRes.z);
  196. int aFixedPrec = int(aComp * 2147483647.0);
  197. int aFixedDiv1 = aFixedPrec / 256;
  198. int aFixedDiv2 = aFixedDiv1 / 256;
  199. int aFixedDiv3 = aFixedDiv2 / 256;
  200. vec4 aPacked = vec4(float(aFixedPrec), float(aFixedDiv1), float(aFixedDiv2), float(aFixedDiv3));
  201. aRes = fract (aPacked * (1.0 / 256.0));
  202. #endif
  203. occFragColor = aRes;
  204. #else
  205. float aRoughness = float(uCurrentLevel) / float(occNbSpecIBLLevels - 1);
  206. occFragColor = vec4 (bakeSpecularMap (aViewDirection, aRoughness), 1.0);
  207. #endif
  208. }