1 THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap
3 uniform int uSamplesNum; //!< number of samples in Monte-Carlo integration
4 uniform int uCurrentLevel; //!< current level of specular IBL map (ignored in case of diffuse map's processing)
5 uniform int uEnvMapSize; //!< one edge's size of source environtment map's zero mipmap level
6 uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap
7 uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap
8 uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)
10 //! Returns coordinates of point theNumber from Hammersley point set having size theSize.
11 vec2 hammersley (in int theNumber,
15 int aNumber = theNumber;
16 float aVanDerCorput = 0.0;
17 for (int i = 0; i < 32; ++i)
21 aVanDerCorput += float(aNumber % 2) / float(aDenominator);
26 return vec2(float(theNumber) / float(theSize), aVanDerCorput);
29 //! This function does importance sampling on hemisphere surface using GGX normal distribution function
30 //! in tangent space (positive z axis is surface normal direction).
31 vec3 importanceSample (in vec2 theHammersleyPoint,
32 in float theRoughness)
34 float aPhi = PI_2 * theHammersleyPoint.x;
35 theRoughness *= theRoughness;
36 theRoughness *= theRoughness;
37 float aCosTheta = sqrt((1.0 - theHammersleyPoint.y) / (1.0 + (theRoughness - 1.0) * theHammersleyPoint.y));
38 float aSinTheta = sqrt(1.0 - aCosTheta * aCosTheta);
39 return vec3(aSinTheta * cos(aPhi),
40 aSinTheta * sin(aPhi),
44 //! This function uniformly generates samples on whole sphere.
45 vec3 sphereUniformSample (in vec2 theHammersleyPoint)
47 float aPhi = PI_2 * theHammersleyPoint.x;
48 float aCosTheta = 2.0 * theHammersleyPoint.y - 1.0;
49 float aSinTheta = sqrt(1.0 - aCosTheta * aCosTheta);
50 return vec3(aSinTheta * cos(aPhi),
51 aSinTheta * sin(aPhi),
55 //! Transforms resulted sampled direction from tangent space to world space considering the surface normal.
56 vec3 fromTangentSpace (in vec3 theVector,
59 vec3 anUp = (abs(theNormal.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
60 vec3 anX = normalize(cross(anUp, theNormal));
61 vec3 anY = cross(theNormal, anX);
62 return anX * theVector.x + anY * theVector.y + theNormal * theVector.z;
65 const float aSHBasisFuncCoeffs[9] = float[9]
78 const float aSHCosCoeffs[9] = float[9]
91 //! Bakes diffuse IBL map's spherical harmonics coefficients.
94 int anIndex = int(gl_FragCoord.x);
95 vec3 aResult = vec3 (0.0);
96 for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
98 vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum);
99 vec3 aDirection = sphereUniformSample (aHammersleyPoint);
101 vec3 aValue = occTextureCube (uEnvMap, cubemapVectorTransform (aDirection, uYCoeff, uZCoeff)).rgb;
106 aBasisFunc[1] = aDirection.x;
107 aBasisFunc[2] = aDirection.y;
108 aBasisFunc[3] = aDirection.z;
110 aBasisFunc[4] = aDirection.x * aDirection.z;
111 aBasisFunc[5] = aDirection.y * aDirection.z;
112 aBasisFunc[6] = aDirection.x * aDirection.y;
114 aBasisFunc[7] = 3.0 * aDirection.z * aDirection.z - 1.0;
115 aBasisFunc[8] = aDirection.x * aDirection.x - aDirection.y * aDirection.y;
117 aResult += aValue * aBasisFunc[anIndex];
120 aResult *= 4.0 * aSHCosCoeffs[anIndex] * aSHBasisFuncCoeffs[anIndex] / float(uSamplesNum);
124 //! Bakes specular IBL map.
125 vec3 bakeSpecularMap (in vec3 theNormal,
126 in float theRoughness)
128 vec3 aResult = vec3(0.0);
129 float aWeightSum = 0.0;
130 int aSamplesNum = (theRoughness == 0.0) ? 1 : uSamplesNum;
131 float aSolidAngleSource = 4.0 * PI / (6.0 * float(uEnvMapSize * uEnvMapSize));
132 for (int aSampleIter = 0; aSampleIter < aSamplesNum; ++aSampleIter)
134 vec2 aHammersleyPoint = hammersley (aSampleIter, aSamplesNum);
135 vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));
136 float aHdotV = aHalf.z;
137 aHalf = fromTangentSpace (aHalf, theNormal);
138 vec3 aLight = -reflect (theNormal, aHalf);
139 float aNdotL = dot (aLight, theNormal);
142 float aSolidAngleSample = 1.0 / (float(aSamplesNum) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);
143 float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / aSolidAngleSource);
144 aResult += occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL;
145 aWeightSum += aNdotL;
148 return aResult / aWeightSum;
153 vec3 aViewDirection = normalize (ViewDirection);
154 if (occNbSpecIBLLevels == 0)
156 occSetFragColor (vec4 (bakeDiffuseSH (), 1.0));
160 occSetFragColor (vec4 (bakeSpecularMap (aViewDirection, float(uCurrentLevel) / float(occNbSpecIBLLevels - 1)), 1.0));