static const char Shaders_PBREnvBaking_fs[] =
"THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap\n"
"\n"
+ "#if (__VERSION__ >= 120)\n"
"uniform int uSamplesNum; //!< number of samples in Monte-Carlo integration\n"
- "uniform int uCurrentLevel; //!< current level of specular IBL map (ignored in case of diffuse map's processing)\n"
- "uniform int uEnvMapSize; //!< one edge's size of source environtment map's zero mipmap level\n"
- "uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap\n"
- "uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap\n"
+ "#else\n"
+ "const int uSamplesNum = 256;\n"
+ "#endif\n"
"uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)\n"
"\n"
+ "#ifdef THE_TO_BAKE_DIFFUSE\n"
+ "uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap\n"
+ "uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap\n"
+ "#endif\n"
+ "\n"
+ "#ifdef THE_TO_BAKE_SPECULAR\n"
+ "uniform int uCurrentLevel; //!< current level of specular IBL map (ignored in case of diffuse map's processing)\n"
+ "uniform float uEnvSolidAngleSource; //!< source solid angle sample computed from one edge's size of source environment map's zero mipmap level\n"
+ "#endif\n"
+ "\n"
"//! Returns coordinates of point theNumber from Hammersley point set having size theSize.\n"
"vec2 hammersley (in int theNumber,\n"
" in int theSize)\n"
" {\n"
" if (aNumber > 0)\n"
" {\n"
- " aVanDerCorput += float(aNumber % 2) / float(aDenominator);\n"
+ " aVanDerCorput += mod(float(aNumber), 2.0) / float(aDenominator);\n"
" aNumber /= 2;\n"
" aDenominator *= 2;\n"
" }\n"
" return anX * theVector.x + anY * theVector.y + theNormal * theVector.z;\n"
"}\n"
"\n"
+ "#ifdef THE_TO_BAKE_DIFFUSE\n"
+ "#if (__VERSION__ >= 120)\n"
"const float aSHBasisFuncCoeffs[9] = float[9]\n"
"(\n"
" 0.282095 * 0.282095,\n"
" 0.315392 * 0.315392,\n"
" 0.546274 * 0.546274\n"
");\n"
- "\n"
"const float aSHCosCoeffs[9] = float[9]\n"
"(\n"
" 3.141593,\n"
" 0.785398,\n"
" 0.785398\n"
");\n"
+ "#else\n"
+ "uniform float aSHBasisFuncCoeffs[9];\n"
+ "uniform float aSHCosCoeffs[9];\n"
+ "#endif\n"
"\n"
"//! Bakes diffuse IBL map's spherical harmonics coefficients.\n"
"vec3 bakeDiffuseSH()\n"
"{\n"
- " int anIndex = int(gl_FragCoord.x);\n"
- " vec3 aResult = vec3 (0.0);\n"
+ " int anId = int(gl_FragCoord.x);\n"
+ " float aCoef;\n"
+ "#if (__VERSION__ >= 120)\n"
+ " aCoef = aSHCosCoeffs[anId] * aSHBasisFuncCoeffs[anId];\n"
+ "#else\n"
+ " if (anId == 0) { aCoef = aSHCosCoeffs[0] * aSHBasisFuncCoeffs[0]; }\n"
+ " else if (anId == 1) { aCoef = aSHCosCoeffs[1] * aSHBasisFuncCoeffs[1]; }\n"
+ " else if (anId == 2) { aCoef = aSHCosCoeffs[2] * aSHBasisFuncCoeffs[2]; }\n"
+ " else if (anId == 3) { aCoef = aSHCosCoeffs[3] * aSHBasisFuncCoeffs[3]; }\n"
+ " else if (anId == 4) { aCoef = aSHCosCoeffs[4] * aSHBasisFuncCoeffs[4]; }\n"
+ " else if (anId == 5) { aCoef = aSHCosCoeffs[5] * aSHBasisFuncCoeffs[5]; }\n"
+ " else if (anId == 6) { aCoef = aSHCosCoeffs[6] * aSHBasisFuncCoeffs[6]; }\n"
+ " else if (anId == 7) { aCoef = aSHCosCoeffs[7] * aSHBasisFuncCoeffs[7]; }\n"
+ " else { aCoef = aSHCosCoeffs[8] * aSHBasisFuncCoeffs[8]; }\n"
+ "#endif\n"
+ " vec3 aRes = vec3 (0.0);\n"
" for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)\n"
" {\n"
" vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum);\n"
- " vec3 aDirection = sphereUniformSample (aHammersleyPoint);\n"
- "\n"
- " vec3 aValue = occTextureCube (uEnvMap, cubemapVectorTransform (aDirection, uYCoeff, uZCoeff)).rgb;\n"
- "\n"
- " float aBasisFunc[9];\n"
- " aBasisFunc[0] = 1.0;\n"
- "\n"
- " aBasisFunc[1] = aDirection.x;\n"
- " aBasisFunc[2] = aDirection.y;\n"
- " aBasisFunc[3] = aDirection.z;\n"
- "\n"
- " aBasisFunc[4] = aDirection.x * aDirection.z;\n"
- " aBasisFunc[5] = aDirection.y * aDirection.z;\n"
- " aBasisFunc[6] = aDirection.x * aDirection.y;\n"
- "\n"
- " aBasisFunc[7] = 3.0 * aDirection.z * aDirection.z - 1.0;\n"
- " aBasisFunc[8] = aDirection.x * aDirection.x - aDirection.y * aDirection.y;\n"
- "\n"
- " aResult += aValue * aBasisFunc[anIndex];\n"
+ " vec3 aDir = sphereUniformSample (aHammersleyPoint);\n"
+ "\n"
+ " vec3 aVal = occTextureCube (uEnvMap, cubemapVectorTransform (aDir, uYCoeff, uZCoeff)).rgb;\n"
+ " #if (__VERSION__ >= 120)\n"
+ " float aFunc[9];\n"
+ " aFunc[0] = 1.0;\n"
+ "\n"
+ " aFunc[1] = aDir.x;\n"
+ " aFunc[2] = aDir.y;\n"
+ " aFunc[3] = aDir.z;\n"
+ "\n"
+ " aFunc[4] = aDir.x * aDir.z;\n"
+ " aFunc[5] = aDir.y * aDir.z;\n"
+ " aFunc[6] = aDir.x * aDir.y;\n"
+ "\n"
+ " aFunc[7] = 3.0 * aDir.z * aDir.z - 1.0;\n"
+ " aFunc[8] = aDir.x * aDir.x - aDir.y * aDir.y;\n"
+ "\n"
+ " aRes += aVal * aFunc[anId];\n"
+ " #else\n"
+ " if (anId == 0) { aRes += aVal * 1.0; }\n"
+ " else if (anId == 1) { aRes += aVal * aDir.x; }\n"
+ " else if (anId == 2) { aRes += aVal * aDir.y; }\n"
+ " else if (anId == 3) { aRes += aVal * aDir.z; }\n"
+ " else if (anId == 4) { aRes += aVal * (aDir.x * aDir.z); }\n"
+ " else if (anId == 5) { aRes += aVal * (aDir.y * aDir.z); }\n"
+ " else if (anId == 6) { aRes += aVal * (aDir.x * aDir.y); }\n"
+ " else if (anId == 7) { aRes += aVal * (3.0 * aDir.z * aDir.z - 1.0); }\n"
+ " else { aRes += aVal * (aDir.x * aDir.x - aDir.y * aDir.y); }\n"
+ " #endif\n"
" }\n"
"\n"
- " aResult *= 4.0 * aSHCosCoeffs[anIndex] * aSHBasisFuncCoeffs[anIndex] / float(uSamplesNum);\n"
- " return aResult;\n"
+ " return 4.0 * aRes * aCoef / float(uSamplesNum);\n"
+ "}\n"
+ "#endif\n"
+ "\n"
+ "#ifdef THE_TO_BAKE_SPECULAR\n"
+ "//! Computes a single sample for specular IBL map.\n"
+ "vec4 specularMapSample (in vec3 theNormal,\n"
+ " in float theRoughness,\n"
+ " in int theNumber,\n"
+ " in int theSize)\n"
+ "{\n"
+ " vec2 aHammersleyPoint = hammersley (theNumber, theSize);\n"
+ " vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));\n"
+ " float aHdotV = aHalf.z;\n"
+ " aHalf = fromTangentSpace (aHalf, theNormal);\n"
+ " vec3 aLight = -reflect (theNormal, aHalf);\n"
+ " float aNdotL = dot (aLight, theNormal);\n"
+ " if (aNdotL > 0.0)\n"
+ " {\n"
+ " float aSolidAngleSample = 1.0 / (float(theSize) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);\n"
+ " float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / uEnvSolidAngleSource);\n"
+ " return vec4 (occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL, aNdotL);\n"
+ " }\n"
+ " return vec4 (0.0);\n"
"}\n"
"\n"
"//! Bakes specular IBL map.\n"
"vec3 bakeSpecularMap (in vec3 theNormal,\n"
" in float theRoughness)\n"
"{\n"
- " vec3 aResult = vec3(0.0);\n"
- " float aWeightSum = 0.0;\n"
- " int aSamplesNum = (theRoughness == 0.0) ? 1 : uSamplesNum;\n"
- " float aSolidAngleSource = 4.0 * PI / (6.0 * float(uEnvMapSize * uEnvMapSize));\n"
- " for (int aSampleIter = 0; aSampleIter < aSamplesNum; ++aSampleIter)\n"
+ " vec4 aResult = vec4(0.0);\n"
+ " if (theRoughness == 0.0)\n"
+ " {\n"
+ " aResult = specularMapSample (theNormal, theRoughness, 0, 1);\n"
+ " }\n"
+ " else\n"
" {\n"
- " vec2 aHammersleyPoint = hammersley (aSampleIter, aSamplesNum);\n"
- " vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));\n"
- " float aHdotV = aHalf.z;\n"
- " aHalf = fromTangentSpace (aHalf, theNormal);\n"
- " vec3 aLight = -reflect (theNormal, aHalf);\n"
- " float aNdotL = dot (aLight, theNormal);\n"
- " if (aNdotL > 0.0)\n"
+ " for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)\n"
" {\n"
- " float aSolidAngleSample = 1.0 / (float(aSamplesNum) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);\n"
- " float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / aSolidAngleSource);\n"
- " aResult += occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL;\n"
- " aWeightSum += aNdotL;\n"
+ " aResult += specularMapSample (theNormal, theRoughness, aSampleIter, uSamplesNum);\n"
" }\n"
" }\n"
- " return aResult / aWeightSum;\n"
+ " return aResult.xyz / aResult.w;\n"
"}\n"
+ "#endif\n"
"\n"
"void main()\n"
"{\n"
" vec3 aViewDirection = normalize (ViewDirection);\n"
- " if (occNbSpecIBLLevels == 0)\n"
- " {\n"
- " occSetFragColor (vec4 (bakeDiffuseSH (), 1.0));\n"
- " }\n"
- " else\n"
- " {\n"
- " occSetFragColor (vec4 (bakeSpecularMap (aViewDirection, float(uCurrentLevel) / float(occNbSpecIBLLevels - 1)), 1.0));\n"
- " }\n"
+ "#ifdef THE_TO_BAKE_DIFFUSE\n"
+ " vec4 aRes = vec4 (bakeDiffuseSH(), 1.0);\n"
+ "#ifdef THE_TO_PACK_FLOAT\n"
+ " int aCompIndex = int(gl_FragCoord.y);\n"
+ " float aComp = aCompIndex == 0 ? aRes.x : (aCompIndex == 1 ? aRes.y : aRes.z);\n"
+ " int aFixedPrec = int(aComp * 2147483647.0);\n"
+ " int aFixedDiv1 = aFixedPrec / 256;\n"
+ " int aFixedDiv2 = aFixedDiv1 / 256;\n"
+ " int aFixedDiv3 = aFixedDiv2 / 256;\n"
+ " vec4 aPacked = vec4(float(aFixedPrec), float(aFixedDiv1), float(aFixedDiv2), float(aFixedDiv3));\n"
+ " aRes = fract (aPacked * (1.0 / 256.0));\n"
+ "#endif\n"
+ " occFragColor = aRes;\n"
+ "#else\n"
+ " float aRoughness = float(uCurrentLevel) / float(occNbSpecIBLLevels - 1);\n"
+ " occFragColor = vec4 (bakeSpecularMap (aViewDirection, aRoughness), 1.0);\n"
+ "#endif\n"
"}\n";