0031275: Visualization, TKOpenGl - handle normal-map texture with Path-Tracing
[occt.git] / src / Shaders / Shaders_PathtraceBase_fs.pxx
index 3db4426..fb32f24 100644 (file)
@@ -49,8 +49,8 @@ static const char Shaders_PathtraceBase_fs[] =
   "  //! Fresnel coefficients of coat layer.\n"
   "  vec3 FresnelCoat;\n"
   "\n"
-  "  //! Fresnel coefficients of base layer.\n"
-  "  vec3 FresnelBase;\n"
+  "  //! Fresnel coefficients of base layer + normal map texture index in W.\n"
+  "  vec4 FresnelBase;\n"
   "};\n"
   "\n"
   "///////////////////////////////////////////////////////////////////////////////////////\n"
@@ -325,7 +325,7 @@ static const char Shaders_PathtraceBase_fs[] =
   "\n"
   "  if (theBSDF.Ks.w > FLT_EPSILON)\n"
   "  {\n"
-  "    aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase, theBSDF.Ks.w);\n"
+  "    aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase.rgb, theBSDF.Ks.w);\n"
   "  }\n"
   "\n"
   "  aBxDF *= UNIT - fresnelMedia (theWo.z, theBSDF.FresnelCoat);\n"
@@ -549,7 +549,7 @@ static const char Shaders_PathtraceBase_fs[] =
   "\n"
   "      if (theBSDF.Ks.w < FLT_EPSILON)\n"
   "      {\n"
-  "        theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase);\n"
+  "        theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase.rgb);\n"
   "\n"
   "        theWi = vec3 (-theWo.x,\n"
   "                      -theWo.y,\n"
@@ -557,7 +557,7 @@ static const char Shaders_PathtraceBase_fs[] =
   "      }\n"
   "      else\n"
   "      {\n"
-  "        theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase, theBSDF.Ks.w, aPDF);\n"
+  "        theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase.rgb, theBSDF.Ks.w, aPDF);\n"
   "      }\n"
   "\n"
   "      aPDF = mix (aPDF, MAXFLOAT, theBSDF.Ks.w < FLT_EPSILON);\n"
@@ -763,6 +763,23 @@ static const char Shaders_PathtraceBase_fs[] =
   "}\n"
   "\n"
   "//=======================================================================\n"
+  "// function : NormalAdaptation\n"
+  "// purpose  : Adapt smooth normal (which may be different from geometry normal) in order to avoid black areas in render\n"
+  "//=======================================================================\n"
+  "bool NormalAdaptation (in vec3 theView, in vec3 theGeometryNormal, inout vec3 theSmoothNormal)\n"
+  "{\n"
+  "  float aMinCos = dot(theView, theGeometryNormal);\n"
+  "  aMinCos = 0.5 * (sqrt(1.0 - aMinCos) + sqrt(1.0 + aMinCos));\n"
+  "  float aCos = dot(theGeometryNormal, theSmoothNormal);\n"
+  "  if (aCos < aMinCos)\n"
+  "  {\n"
+  "    theSmoothNormal = aMinCos * theGeometryNormal + normalize(theSmoothNormal - aCos * theGeometryNormal) * sqrt(1.0 - aMinCos * aMinCos);\n"
+  "    return true;\n"
+  "  }\n"
+  "  return false;\n"
+  "}\n"
+  "\n"
+  "//=======================================================================\n"
   "// function : PathTrace\n"
   "// purpose  : Calculates radiance along the given ray\n"
   "//=======================================================================\n"
@@ -783,12 +800,12 @@ static const char Shaders_PathtraceBase_fs[] =
   "  {\n"
   "    SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n"
   "\n"
-  "    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n"
+  "    STriangle aTriangle = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n"
   "\n"
   "    // check implicit path\n"
   "    vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF);\n"
   "\n"
-  "    if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)\n"
+  "    if (any (greaterThan (aLe, ZERO)) || aTriangle.TriIndex.x == -1)\n"
   "    {\n"
   "      float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f :\n"
   "        aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
@@ -819,31 +836,30 @@ static const char Shaders_PathtraceBase_fs[] =
   "    SBSDF aBSDF;\n"
   "\n"
   "    // fetch BxDF weights\n"
-  "    aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w));\n"
-  "    aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w));\n"
-  "    aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w));\n"
-  "    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w));\n"
+  "    aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriangle.TriIndex.w));\n"
+  "    aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriangle.TriIndex.w));\n"
+  "    aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriangle.TriIndex.w));\n"
+  "    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriangle.TriIndex.w));\n"
   "\n"
   "    // fetch Fresnel reflectance for both layers\n"
-  "    aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;\n"
-  "    aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;\n"
+  "    aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriangle.TriIndex.w)).xyz;\n"
+  "    aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriangle.TriIndex.w));\n"
   "\n"
-  "    vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w));\n"
+  "    vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriangle.TriIndex.w));\n"
   "\n"
   "    // compute smooth normal (in parallel with fetch)\n"
-  "    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n"
+  "    vec3 aNormal = SmoothNormal (aHit.UV, aTriangle.TriIndex);\n"
   "    aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n"
   "                               dot (aInvTransf1, aNormal),\n"
   "                               dot (aInvTransf2, aNormal)));\n"
   "\n"
-  "    SLocalSpace aSpace = buildLocalSpace (aNormal);\n"
-  "\n"
   "#ifdef USE_TEXTURES\n"
-  "    if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || anLE.w >= 0.0)\n"
+  "    if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || aBSDF.FresnelBase.w >=0.0 || anLE.w >= 0.0)\n"
   "    {\n"
-  "      vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);\n"
-  "      vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));\n"
-  "      vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));\n"
+  "      vec2 aUVs[3];\n"
+  "      vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriangle.TriIndex, aUVs), 0.f, 1.f);\n"
+  "      vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriangle.TriIndex.w));\n"
+  "      vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriangle.TriIndex.w));\n"
   "      aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n"
   "                           dot (aTrsfRow2, aTexCoord));\n"
   "\n"
@@ -858,15 +874,15 @@ static const char Shaders_PathtraceBase_fs[] =
   "        float aPbrRough2 = aTexMetRough.y * aTexMetRough.y;\n"
   "        aBSDF.Ks.a *= aPbrRough2;\n"
   "        // when using metal-roughness texture, global metalness of material (encoded in FresnelBase) is expected to be 1.0 so that Kd will be 0.0\n"
-  "        aBSDF.Kd.rgb = aBSDF.FresnelBase * (1.0 - aPbrMetal);\n"
-  "        aBSDF.FresnelBase *= aPbrMetal;\n"
+  "        aBSDF.Kd.rgb = aBSDF.FresnelBase.rgb * (1.0 - aPbrMetal);\n"
+  "        aBSDF.FresnelBase.rgb *= aPbrMetal;\n"
   "      }\n"
   "      if (aBSDF.Kd.w >= 0.0)\n"
   "      {\n"
   "        vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.0);\n"
   "        vec3 aDiff = aTexColor.rgb * aTexColor.a;\n"
   "        aBSDF.Kd.rgb *= aDiff;\n"
-  "        aBSDF.FresnelBase *= aDiff;\n"
+  "        aBSDF.FresnelBase.rgb *= aDiff;\n"
   "        if (aTexColor.a != 1.0)\n"
   "        {\n"
   "          // mix transparency BTDF with texture alpha-channel\n"
@@ -874,8 +890,25 @@ static const char Shaders_PathtraceBase_fs[] =
   "          aBSDF.Kt.rgb = (UNIT - aTexColor.aaa) + aTexColor.a * aBSDF.Kt.rgb;\n"
   "        }\n"
   "      }\n"
+  "      #ifndef IGNORE_NORMAL_MAP\n"
+  "      if (aBSDF.FresnelBase.w >= 0.0)\n"
+  "      {\n"
+  "        for (int i = 0 ; i < 3; ++i)\n"
+  "        {\n"
+  "          aUVs[i] = vec2 (dot (aTrsfRow1, vec4(aUVs[i], 0.0, 1.0)),\n"
+  "                          dot (aTrsfRow2, vec4(aUVs[i], 0.0, 1.0)));\n"
+  "        }\n"
+  "        vec3 aMapNormalValue = textureLod (sampler2D (uTextureSamplers[int (aBSDF.FresnelBase.w)]), aTexCoord.st, 0.0).xyz;\n"
+  "        mat2 aDeltaUVMatrix = mat2 (aUVs[1] - aUVs[0], aUVs[1] - aUVs[2]);\n"
+  "        mat2x3 aDeltaVectorMatrix = mat2x3 (aTriangle.Points[1] - aTriangle.Points[0], aTriangle.Points[1] - aTriangle.Points[2]);\n"
+  "        aNormal = TangentSpaceNormal (aDeltaUVMatrix, aDeltaVectorMatrix, aMapNormalValue, aNormal, true);\n"
+  "      }\n"
+  "      #endif\n"
   "    }\n"
   "#endif\n"
+  "    NormalAdaptation (-theRay.Direct, aHit.Normal, aNormal);\n"
+  "    aHit.Normal = aNormal;\n"
+  "    SLocalSpace aSpace = buildLocalSpace (aNormal);\n"
   "\n"
   "    if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))\n"
   "    {\n"
@@ -924,7 +957,7 @@ static const char Shaders_PathtraceBase_fs[] =
   "\n"
   "    if (aInMedium) // handle attenuation\n"
   "    {\n"
-  "      vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriIndex.w));\n"
+  "      vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriangle.TriIndex.w));\n"
   "\n"
   "      aThroughput *= exp (-aHit.Time * aScattering.w * (UNIT - aScattering.rgb));\n"
   "    }\n"