123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap
- #if (__VERSION__ >= 120)
- uniform int uSamplesNum; //!< number of samples in Monte-Carlo integration
- #else
- const int uSamplesNum = 256;
- #endif
- uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)
- #ifdef THE_TO_BAKE_DIFFUSE
- uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap
- uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap
- #endif
- #ifdef THE_TO_BAKE_SPECULAR
- uniform int uCurrentLevel; //!< current level of specular IBL map (ignored in case of diffuse map's processing)
- uniform float uEnvSolidAngleSource; //!< source solid angle sample computed from one edge's size of source environment map's zero mipmap level
- #endif
- //! Returns coordinates of point theNumber from Hammersley point set having size theSize.
- vec2 hammersley (in int theNumber,
- in int theSize)
- {
- int aDenominator = 2;
- int aNumber = theNumber;
- float aVanDerCorput = 0.0;
- for (int i = 0; i < 32; ++i)
- {
- if (aNumber > 0)
- {
- aVanDerCorput += mod(float(aNumber), 2.0) / float(aDenominator);
- aNumber /= 2;
- aDenominator *= 2;
- }
- }
- return vec2(float(theNumber) / float(theSize), aVanDerCorput);
- }
- //! This function does importance sampling on hemisphere surface using GGX normal distribution function
- //! in tangent space (positive z axis is surface normal direction).
- vec3 importanceSample (in vec2 theHammersleyPoint,
- in float theRoughness)
- {
- float aPhi = PI_2 * theHammersleyPoint.x;
- theRoughness *= theRoughness;
- theRoughness *= theRoughness;
- float aCosTheta = sqrt((1.0 - theHammersleyPoint.y) / (1.0 + (theRoughness - 1.0) * theHammersleyPoint.y));
- float aSinTheta = sqrt(1.0 - aCosTheta * aCosTheta);
- return vec3(aSinTheta * cos(aPhi),
- aSinTheta * sin(aPhi),
- aCosTheta);
- }
- //! This function uniformly generates samples on whole sphere.
- vec3 sphereUniformSample (in vec2 theHammersleyPoint)
- {
- float aPhi = PI_2 * theHammersleyPoint.x;
- float aCosTheta = 2.0 * theHammersleyPoint.y - 1.0;
- float aSinTheta = sqrt(1.0 - aCosTheta * aCosTheta);
- return vec3(aSinTheta * cos(aPhi),
- aSinTheta * sin(aPhi),
- aCosTheta);
- }
- //! Transforms resulted sampled direction from tangent space to world space considering the surface normal.
- vec3 fromTangentSpace (in vec3 theVector,
- in vec3 theNormal)
- {
- vec3 anUp = (abs(theNormal.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- vec3 anX = normalize(cross(anUp, theNormal));
- vec3 anY = cross(theNormal, anX);
- return anX * theVector.x + anY * theVector.y + theNormal * theVector.z;
- }
- #ifdef THE_TO_BAKE_DIFFUSE
- #if (__VERSION__ >= 120)
- const float aSHBasisFuncCoeffs[9] = float[9]
- (
- 0.282095 * 0.282095,
- 0.488603 * 0.488603,
- 0.488603 * 0.488603,
- 0.488603 * 0.488603,
- 1.092548 * 1.092548,
- 1.092548 * 1.092548,
- 1.092548 * 1.092548,
- 0.315392 * 0.315392,
- 0.546274 * 0.546274
- );
- const float aSHCosCoeffs[9] = float[9]
- (
- 3.141593,
- 2.094395,
- 2.094395,
- 2.094395,
- 0.785398,
- 0.785398,
- 0.785398,
- 0.785398,
- 0.785398
- );
- #else
- uniform float aSHBasisFuncCoeffs[9];
- uniform float aSHCosCoeffs[9];
- #endif
- //! Bakes diffuse IBL map's spherical harmonics coefficients.
- vec3 bakeDiffuseSH()
- {
- int anId = int(gl_FragCoord.x);
- float aCoef;
- #if (__VERSION__ >= 120)
- aCoef = aSHCosCoeffs[anId] * aSHBasisFuncCoeffs[anId];
- #else
- if (anId == 0) { aCoef = aSHCosCoeffs[0] * aSHBasisFuncCoeffs[0]; }
- else if (anId == 1) { aCoef = aSHCosCoeffs[1] * aSHBasisFuncCoeffs[1]; }
- else if (anId == 2) { aCoef = aSHCosCoeffs[2] * aSHBasisFuncCoeffs[2]; }
- else if (anId == 3) { aCoef = aSHCosCoeffs[3] * aSHBasisFuncCoeffs[3]; }
- else if (anId == 4) { aCoef = aSHCosCoeffs[4] * aSHBasisFuncCoeffs[4]; }
- else if (anId == 5) { aCoef = aSHCosCoeffs[5] * aSHBasisFuncCoeffs[5]; }
- else if (anId == 6) { aCoef = aSHCosCoeffs[6] * aSHBasisFuncCoeffs[6]; }
- else if (anId == 7) { aCoef = aSHCosCoeffs[7] * aSHBasisFuncCoeffs[7]; }
- else { aCoef = aSHCosCoeffs[8] * aSHBasisFuncCoeffs[8]; }
- #endif
- vec3 aRes = vec3 (0.0);
- for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
- {
- vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum);
- vec3 aDir = sphereUniformSample (aHammersleyPoint);
- vec3 aVal = occTextureCube (uEnvMap, cubemapVectorTransform (aDir, uYCoeff, uZCoeff)).rgb;
- #if (__VERSION__ >= 120)
- float aFunc[9];
- aFunc[0] = 1.0;
- aFunc[1] = aDir.x;
- aFunc[2] = aDir.y;
- aFunc[3] = aDir.z;
- aFunc[4] = aDir.x * aDir.z;
- aFunc[5] = aDir.y * aDir.z;
- aFunc[6] = aDir.x * aDir.y;
- aFunc[7] = 3.0 * aDir.z * aDir.z - 1.0;
- aFunc[8] = aDir.x * aDir.x - aDir.y * aDir.y;
- aRes += aVal * aFunc[anId];
- #else
- if (anId == 0) { aRes += aVal * 1.0; }
- else if (anId == 1) { aRes += aVal * aDir.x; }
- else if (anId == 2) { aRes += aVal * aDir.y; }
- else if (anId == 3) { aRes += aVal * aDir.z; }
- else if (anId == 4) { aRes += aVal * (aDir.x * aDir.z); }
- else if (anId == 5) { aRes += aVal * (aDir.y * aDir.z); }
- else if (anId == 6) { aRes += aVal * (aDir.x * aDir.y); }
- else if (anId == 7) { aRes += aVal * (3.0 * aDir.z * aDir.z - 1.0); }
- else { aRes += aVal * (aDir.x * aDir.x - aDir.y * aDir.y); }
- #endif
- }
- return 4.0 * aRes * aCoef / float(uSamplesNum);
- }
- #endif
- #ifdef THE_TO_BAKE_SPECULAR
- //! Computes a single sample for specular IBL map.
- vec4 specularMapSample (in vec3 theNormal,
- in float theRoughness,
- in int theNumber,
- in int theSize)
- {
- vec2 aHammersleyPoint = hammersley (theNumber, theSize);
- vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));
- float aHdotV = aHalf.z;
- aHalf = fromTangentSpace (aHalf, theNormal);
- vec3 aLight = -reflect (theNormal, aHalf);
- float aNdotL = dot (aLight, theNormal);
- if (aNdotL > 0.0)
- {
- float aSolidAngleSample = 1.0 / (float(theSize) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);
- float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / uEnvSolidAngleSource);
- return vec4 (occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL, aNdotL);
- }
- return vec4 (0.0);
- }
- //! Bakes specular IBL map.
- vec3 bakeSpecularMap (in vec3 theNormal,
- in float theRoughness)
- {
- vec4 aResult = vec4(0.0);
- if (theRoughness == 0.0)
- {
- aResult = specularMapSample (theNormal, theRoughness, 0, 1);
- }
- else
- {
- for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
- {
- aResult += specularMapSample (theNormal, theRoughness, aSampleIter, uSamplesNum);
- }
- }
- return aResult.xyz / aResult.w;
- }
- #endif
- void main()
- {
- vec3 aViewDirection = normalize (ViewDirection);
- #ifdef THE_TO_BAKE_DIFFUSE
- vec4 aRes = vec4 (bakeDiffuseSH(), 1.0);
- #ifdef THE_TO_PACK_FLOAT
- int aCompIndex = int(gl_FragCoord.y);
- float aComp = aCompIndex == 0 ? aRes.x : (aCompIndex == 1 ? aRes.y : aRes.z);
- int aFixedPrec = int(aComp * 2147483647.0);
- int aFixedDiv1 = aFixedPrec / 256;
- int aFixedDiv2 = aFixedDiv1 / 256;
- int aFixedDiv3 = aFixedDiv2 / 256;
- vec4 aPacked = vec4(float(aFixedPrec), float(aFixedDiv1), float(aFixedDiv2), float(aFixedDiv3));
- aRes = fract (aPacked * (1.0 / 256.0));
- #endif
- occFragColor = aRes;
- #else
- float aRoughness = float(uCurrentLevel) / float(occNbSpecIBLLevels - 1);
- occFragColor = vec4 (bakeSpecularMap (aViewDirection, aRoughness), 1.0);
- #endif
- }
|