0031279: Visualization, TKOpenGl - environment background is misplaced within Ray...
[occt.git] / src / Shaders / PBREnvBaking.fs
CommitLineData
67312b79 1THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap
2
3uniform int uSamplesNum; //!< number of samples in Monte-Carlo integration
4uniform int uCurrentLevel; //!< current level of specular IBL map (ignored in case of diffuse map's processing)
5uniform int uEnvMapSize; //!< one edge's size of source environtment map's zero mipmap level
6uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap
7uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap
8uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)
9
10//! Returns coordinates of point theNumber from Hammersley point set having size theSize.
11vec2 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).
31vec3 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.
45vec3 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.
56vec3 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
65const 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
78const 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.
92vec3 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.
125vec3 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
151void 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}