67312b79 |
1 | THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap |
2 | |
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) |
9 | |
10 | //! Returns coordinates of point theNumber from Hammersley point set having size theSize. |
11 | vec2 hammersley (in int theNumber, |
12 | in int theSize) |
13 | { |
14 | int aDenominator = 2; |
15 | int aNumber = theNumber; |
16 | float aVanDerCorput = 0.0; |
17 | for (int i = 0; i < 32; ++i) |
18 | { |
19 | if (aNumber > 0) |
20 | { |
21 | aVanDerCorput += float(aNumber % 2) / float(aDenominator); |
22 | aNumber /= 2; |
23 | aDenominator *= 2; |
24 | } |
25 | } |
26 | return vec2(float(theNumber) / float(theSize), aVanDerCorput); |
27 | } |
28 | |
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) |
33 | { |
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), |
41 | aCosTheta); |
42 | } |
43 | |
44 | //! This function uniformly generates samples on whole sphere. |
45 | vec3 sphereUniformSample (in vec2 theHammersleyPoint) |
46 | { |
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), |
52 | aCosTheta); |
53 | } |
54 | |
55 | //! Transforms resulted sampled direction from tangent space to world space considering the surface normal. |
56 | vec3 fromTangentSpace (in vec3 theVector, |
57 | in vec3 theNormal) |
58 | { |
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; |
63 | } |
64 | |
65 | const float aSHBasisFuncCoeffs[9] = float[9] |
66 | ( |
67 | 0.282095 * 0.282095, |
68 | 0.488603 * 0.488603, |
69 | 0.488603 * 0.488603, |
70 | 0.488603 * 0.488603, |
71 | 1.092548 * 1.092548, |
72 | 1.092548 * 1.092548, |
73 | 1.092548 * 1.092548, |
74 | 0.315392 * 0.315392, |
75 | 0.546274 * 0.546274 |
76 | ); |
77 | |
78 | const float aSHCosCoeffs[9] = float[9] |
79 | ( |
80 | 3.141593, |
81 | 2.094395, |
82 | 2.094395, |
83 | 2.094395, |
84 | 0.785398, |
85 | 0.785398, |
86 | 0.785398, |
87 | 0.785398, |
88 | 0.785398 |
89 | ); |
90 | |
91 | //! Bakes diffuse IBL map's spherical harmonics coefficients. |
92 | vec3 bakeDiffuseSH() |
93 | { |
94 | int anIndex = int(gl_FragCoord.x); |
95 | vec3 aResult = vec3 (0.0); |
96 | for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter) |
97 | { |
98 | vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum); |
99 | vec3 aDirection = sphereUniformSample (aHammersleyPoint); |
100 | |
101 | vec3 aValue = occTextureCube (uEnvMap, cubemapVectorTransform (aDirection, uYCoeff, uZCoeff)).rgb; |
102 | |
103 | float aBasisFunc[9]; |
104 | aBasisFunc[0] = 1.0; |
105 | |
106 | aBasisFunc[1] = aDirection.x; |
107 | aBasisFunc[2] = aDirection.y; |
108 | aBasisFunc[3] = aDirection.z; |
109 | |
110 | aBasisFunc[4] = aDirection.x * aDirection.z; |
111 | aBasisFunc[5] = aDirection.y * aDirection.z; |
112 | aBasisFunc[6] = aDirection.x * aDirection.y; |
113 | |
114 | aBasisFunc[7] = 3.0 * aDirection.z * aDirection.z - 1.0; |
115 | aBasisFunc[8] = aDirection.x * aDirection.x - aDirection.y * aDirection.y; |
116 | |
117 | aResult += aValue * aBasisFunc[anIndex]; |
118 | } |
119 | |
120 | aResult *= 4.0 * aSHCosCoeffs[anIndex] * aSHBasisFuncCoeffs[anIndex] / float(uSamplesNum); |
121 | return aResult; |
122 | } |
123 | |
124 | //! Bakes specular IBL map. |
125 | vec3 bakeSpecularMap (in vec3 theNormal, |
126 | in float theRoughness) |
127 | { |
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) |
133 | { |
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); |
140 | if (aNdotL > 0.0) |
141 | { |
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; |
146 | } |
147 | } |
148 | return aResult / aWeightSum; |
149 | } |
150 | |
151 | void main() |
152 | { |
153 | vec3 aViewDirection = normalize (ViewDirection); |
154 | if (occNbSpecIBLLevels == 0) |
155 | { |
156 | occSetFragColor (vec4 (bakeDiffuseSH (), 1.0)); |
157 | } |
158 | else |
159 | { |
160 | occSetFragColor (vec4 (bakeSpecularMap (aViewDirection, float(uCurrentLevel) / float(occNbSpecIBLLevels - 1)), 1.0)); |
161 | } |
162 | } |