0031096: Visualization, TKOpenGl - support metallic-roughness texture mapping IR-2019-11-29
authoriko <iko@opencascade.com>
Thu, 7 Nov 2019 13:52:53 +0000 (16:52 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 29 Nov 2019 17:36:23 +0000 (20:36 +0300)
OpenGl_ShaderManager - metallic-roughness, emissive, occlusion
and normal texture maps are now supported by PBR.
Emissive, occlusion and normal texture maps are now supported by Phong shading model.
Path-Tracing now handles metallic-roughness and emissive texture maps.

Graphic3d_TextureUnit enumeration has been extended by
new values corresponding to supported texture maps.

OpenGl_TextureSet and OpenGl_ShaderProgram have been extended with
bitmask Graphic3d_TextureSetBits identifying texture slots read from GLSL Program
and slots defined within Texture Set to avoid undefined behavior by binding mock textures.

OpenGl_TextureSet now duplicates texture unit information to handle
textures shared across multiple slots (like Occlusion [R] + Metallic-Roughness [GB]).

OpenGl_Context::BindTextures() has been extended with active GLSL program paramter
to set mock textures to texture units used by program but undefined by texture set.
OpenGl_Workspace::ApplyAspects() has been extended with parameter to avoid bining texture set.

35 files changed:
src/Graphic3d/FILES
src/Graphic3d/Graphic3d_BSDF.cxx
src/Graphic3d/Graphic3d_ShaderProgram.cxx
src/Graphic3d/Graphic3d_ShaderProgram.hxx
src/Graphic3d/Graphic3d_TextureSetBits.hxx [new file with mode: 0644]
src/Graphic3d/Graphic3d_TextureUnit.hxx
src/OpenGl/OpenGl_AspectsTextureSet.cxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_LayerList.cxx
src/OpenGl/OpenGl_PrimitiveArray.cxx
src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_ShaderProgram.cxx
src/OpenGl/OpenGl_ShaderProgram.hxx
src/OpenGl/OpenGl_Structure.cxx
src/OpenGl/OpenGl_Text.cxx
src/OpenGl/OpenGl_Texture.hxx
src/OpenGl/OpenGl_TextureSet.cxx
src/OpenGl/OpenGl_TextureSet.hxx
src/OpenGl/OpenGl_View.cxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/OpenGl/OpenGl_View_Redraw.cxx
src/OpenGl/OpenGl_Workspace.cxx
src/OpenGl/OpenGl_Workspace.hxx
src/Shaders/Declarations.glsl
src/Shaders/DeclarationsImpl.glsl
src/Shaders/PathtraceBase.fs
src/Shaders/Shaders_DeclarationsImpl_glsl.pxx
src/Shaders/Shaders_Declarations_glsl.pxx
src/Shaders/Shaders_PathtraceBase_fs.pxx
src/XCAFDoc/XCAFDoc_VisMaterial.cxx
src/XCAFPrs/XCAFPrs_Texture.cxx
tests/v3d/raytrace/helmet [new file with mode: 0644]

index 7fe5539..31ac882 100755 (executable)
@@ -164,6 +164,7 @@ Graphic3d_TextureRoot.hxx
 Graphic3d_TextureUnit.hxx
 Graphic3d_TextureSet.cxx
 Graphic3d_TextureSet.hxx
+Graphic3d_TextureSetBits.hxx
 Graphic3d_ToneMappingMethod.hxx
 Graphic3d_TransformError.hxx
 Graphic3d_TransformPers.hxx
index f3e6710..81d53fb 100644 (file)
@@ -208,5 +208,6 @@ Graphic3d_BSDF Graphic3d_BSDF::CreateMetallicRoughness (const Graphic3d_PBRMater
   aBsdf.Ks.SetValues (Graphic3d_Vec3 (thePbr.Alpha()), aRougness2);
   aBsdf.Kt = Graphic3d_Vec3 (1.0f - thePbr.Alpha());
   aBsdf.Kd = aDiff * (1.0f - thePbr.Metallic());
+  aBsdf.Le = thePbr.Emission();
   return aBsdf;
 }
index e08774d..aef9958 100755 (executable)
@@ -80,6 +80,7 @@ Graphic3d_ShaderProgram::Graphic3d_ShaderProgram()
 : myNbLightsMax (THE_MAX_LIGHTS_DEFAULT),
   myNbClipPlanesMax (THE_MAX_CLIP_PLANES_DEFAULT),
   myNbFragOutputs (THE_NB_FRAG_OUTPUTS),
+  myTextureSetBits (Graphic3d_TextureSetBits_NONE),
   myHasDefSampler (true),
   myHasAlphaTest (false),
   myHasWeightOitOutput (false),
index 2aa7f19..b039067 100755 (executable)
@@ -20,6 +20,7 @@
 #include <Graphic3d_ShaderObject.hxx>
 #include <Graphic3d_ShaderVariable.hxx>
 #include <Graphic3d_TextureParams.hxx>
+#include <Graphic3d_TextureSetBits.hxx>
 #include <NCollection_Sequence.hxx>
 
 //! List of shader objects.
@@ -152,12 +153,18 @@ public:
   void SetWeightOitOutput (Standard_Boolean theOutput) { myHasWeightOitOutput = theOutput; }
 
   //! Return TRUE if standard program header should define functions and variables used in PBR pipeline.
-  //! FALSE by default
+  //! FALSE by default.
   Standard_Boolean IsPBR() const { return myIsPBR; }
 
   //! Sets whether standard program header should define functions and variables used in PBR pipeline.
   void SetPBR (Standard_Boolean theIsPBR) { myIsPBR = theIsPBR; }
 
+  //! Return texture units declared within the program, @sa Graphic3d_TextureSetBits.
+  Standard_Integer TextureSetBits() const { return myTextureSetBits; }
+
+  //! Set texture units declared within the program.
+  void SetTextureSetBits (Standard_Integer theBits) { myTextureSetBits = theBits; }
+
   //! Pushes custom uniform variable to the program.
   //! The list of pushed variables is automatically cleared after applying to GLSL program.
   //! Thus after program recreation even unchanged uniforms should be pushed anew.
@@ -208,6 +215,7 @@ private:
   Standard_Integer              myNbLightsMax;   //!< length of array of light sources (THE_MAX_LIGHTS)
   Standard_Integer              myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
   Standard_Integer              myNbFragOutputs; //!< length of array of Fragment Shader outputs (THE_NB_FRAG_OUTPUTS)
+  Standard_Integer              myTextureSetBits;//!< texture units declared within the program, @sa Graphic3d_TextureSetBits
   Standard_Boolean              myHasDefSampler; //!< flag indicating that program defines default texture sampler occSampler0
   Standard_Boolean              myHasAlphaTest;       //!< flag indicating that Fragment Shader performs alpha test
   Standard_Boolean              myHasWeightOitOutput; //!< flag indicating that Fragment Shader includes weighted OIT coverage
diff --git a/src/Graphic3d/Graphic3d_TextureSetBits.hxx b/src/Graphic3d/Graphic3d_TextureSetBits.hxx
new file mode 100644 (file)
index 0000000..3a7e96d
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Graphic3d_TextureSetBits_HeaderFile
+#define _Graphic3d_TextureSetBits_HeaderFile
+
+#include <Graphic3d_TextureUnit.hxx>
+
+//! Standard texture units combination bits.
+enum Graphic3d_TextureSetBits
+{
+  Graphic3d_TextureSetBits_NONE              = 0,
+  Graphic3d_TextureSetBits_BaseColor         = (unsigned int )(1 << int(Graphic3d_TextureUnit_BaseColor)),
+  Graphic3d_TextureSetBits_Emissive          = (unsigned int )(1 << int(Graphic3d_TextureUnit_Emissive)),
+  Graphic3d_TextureSetBits_Occlusion         = (unsigned int )(1 << int(Graphic3d_TextureUnit_Occlusion)),
+  Graphic3d_TextureSetBits_Normal            = (unsigned int )(1 << int(Graphic3d_TextureUnit_Normal)),
+  Graphic3d_TextureSetBits_MetallicRoughness = (unsigned int )(1 << int(Graphic3d_TextureUnit_MetallicRoughness)),
+};
+
+#endif // _Graphic3d_TextureSetBits_HeaderFile
index 477147b..f554b8e 100644 (file)
@@ -35,17 +35,54 @@ enum Graphic3d_TextureUnit
   Graphic3d_TextureUnit_14,
   Graphic3d_TextureUnit_15,
 
-  Graphic3d_TextureUnit_BaseColor         = Graphic3d_TextureUnit_0, //!< base color of the material
-  //Graphic3d_TextureUnit_Normal            = Graphic3d_TextureUnit_1, //!< tangent space normal map
-  //Graphic3d_TextureUnit_MetallicRoughness = Graphic3d_TextureUnit_2, //!< metalness+roughness of the material
-  //Graphic3d_TextureUnit_Emissive          = Graphic3d_TextureUnit_3, //!< emissive map controls the color and intensity of the light being emitted by the material
-  //Graphic3d_TextureUnit_Occlusion         = Graphic3d_TextureUnit_4, //!< occlusion map indicating areas of indirect lighting
+  // aliases
 
-  Graphic3d_TextureUnit_EnvMap = Graphic3d_TextureUnit_0  //!< environment cubemap for background
+  //! sampler2D occSamplerBaseColor.
+  //! RGB(A) base color of the material and alpha mask/opacity.
+  Graphic3d_TextureUnit_BaseColor = Graphic3d_TextureUnit_0,
+  //! sampler2D occSamplerEmissive.
+  //! RGB emissive map controls the color and intensity of the light being emitted by the material.
+  Graphic3d_TextureUnit_Emissive  = Graphic3d_TextureUnit_1,
+  //! sampler2D occSamplerOcclusion.
+  //! Occlusion map indicating areas of indirect lighting.
+  //! Encoded into RED channel, with 1.0 meaning no occlusion (full color intensity) and 0.0 complete occlusion (black).
+  Graphic3d_TextureUnit_Occlusion = Graphic3d_TextureUnit_2,
+  //! sampler2D occSamplerNormal.
+  //! XYZ tangent space normal map.
+  Graphic3d_TextureUnit_Normal    = Graphic3d_TextureUnit_3,
+  //! sampler2D occSamplerMetallicRoughness.
+  //! Metalness + roughness of the material.
+  //! Encoded into GREEN (roughness) + BLUE (metallic) channels,
+  //! so that it can be optionally combined with occlusion texture (RED channel).
+  Graphic3d_TextureUnit_MetallicRoughness = Graphic3d_TextureUnit_4,
+
+  //! samplerCube occSampler0.
+  //! Environment cubemap for background. Rendered by dedicated program and normally occupies first texture unit.
+  Graphic3d_TextureUnit_EnvMap = Graphic3d_TextureUnit_0,
+
+  //! sampler2D occSamplerPointSprite.
+  //! Sprite alpha-mask or RGBA image mapped using point UV, additional to BaseColor (mapping using vertex UV).
+  //! This texture unit is set Graphic3d_TextureUnit_1, so that it can be combined with Graphic3d_TextureUnit_BaseColor,
+  //! while other texture maps (normal map and others) are unexpected and unsupported for points.
+  //! Note that it can be overridden to Graphic3d_TextureUnit_0 for FFP fallback on hardware without multi-texturing.
+  Graphic3d_TextureUnit_PointSprite = Graphic3d_TextureUnit_1,
+
+  //! sampler2D occEnvLUT.
+  //! Lookup table for approximated PBR environment lighting.
+  //! Configured as index at the end of available texture units - 3.
+  Graphic3d_TextureUnit_PbrEnvironmentLUT = -3,
+  //! sampler2D occDiffIBLMapSHCoeffs.
+  //! Diffuse (irradiance) IBL map's spherical harmonics coefficients baked for PBR from environment cubemap image.
+  //! Configured as index at the end of available texture units - 2.
+  Graphic3d_TextureUnit_PbrIblDiffuseSH   = -2,
+  //! samplerCube occSpecIBLMap.
+  //! Specular IBL (Image-Based Lighting) environment map baked for PBR from environment cubemap image.
+  //! Configured as index at the end of available texture units - 1.
+  Graphic3d_TextureUnit_PbrIblSpecular    = -1,
 };
 enum
 {
-  Graphic3d_TextureUnit_NB = Graphic3d_TextureUnit_15 + 1
+  Graphic3d_TextureUnit_NB = Graphic3d_TextureUnit_15 + 1,
 };
 
 #endif // _Graphic3d_TextureUnit_HeaderFile
index 2ad9729..150361b 100644 (file)
@@ -131,6 +131,7 @@ void OpenGl_AspectsTextureSet::UpdateRediness (const Handle(Graphic3d_Aspects)&
     {
       // just invalidate texture parameters
       aResource->Sampler()->SetParameters (aTexture->GetParams());
+      aResIter.ChangeUnit() = aResource->Sampler()->Parameters()->TextureUnit();
     }
   }
 }
@@ -192,6 +193,8 @@ void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
     }
   }
 
+  Standard_Integer& aTextureSetBits = myTextures[0]->ChangeTextureSetBits();
+  aTextureSetBits = Graphic3d_TextureSetBits_NONE;
   if (theAspect->ToMapTexture())
   {
     Graphic3d_TextureSet::Iterator aTextureIter (aNewTextureSet);
@@ -208,6 +211,7 @@ void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
         {
           if (aResource->Init(theCtx, aTexture))
           {
+            aResIter0.ChangeUnit() = aResource->Sampler()->Parameters()->TextureUnit();
             aResource->Sampler()->SetParameters(aTexture->GetParams());
             aResource->SetRevision (aTexture->Revision());
           }
@@ -254,6 +258,14 @@ void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
           }
           aResource->Sampler()->SetParameters (aTexture->GetParams());
         }
+
+        // update occupation of texture units
+        const Graphic3d_TextureUnit aTexUnit = aResource->Sampler()->Parameters()->TextureUnit();
+        aResIter0.ChangeUnit() = aTexUnit;
+        if (aTexUnit >= Graphic3d_TextureUnit_0 && aTexUnit <= Graphic3d_TextureUnit_5)
+        {
+          aTextureSetBits |= (1 << int(aTexUnit));
+        }
       }
     }
   }
@@ -261,6 +273,8 @@ void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
   if (hasSprite)
   {
     myTextures[0]->ChangeLast() = theSprite;
+    myTextures[0]->ChangeLastUnit() = theCtx->SpriteTextureUnit();
+    // Graphic3d_TextureUnit_PointSprite
     if (!theSprite.IsNull())
     {
       theSprite ->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
@@ -275,12 +289,15 @@ void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
     return;
   }
 
+  myTextures[1]->ChangeTextureSetBits() = aTextureSetBits;
   for (OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]), aResIter1 (myTextures[1]); aResIter0.More(); aResIter0.Next(), aResIter1.Next())
   {
     aResIter1.ChangeValue() = aResIter0.Value();
+    aResIter1.ChangeUnit()  = aResIter0.Unit();
   }
   if (hasSprite)
   {
     myTextures[1]->ChangeLast() = theSpriteA;
+    myTextures[1]->ChangeLastUnit() = theCtx->SpriteTextureUnit();
   }
 }
index d61be5b..a84e125 100644 (file)
@@ -204,16 +204,17 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myIsInitialized (Standard_False),
   myIsStereoBuffers (Standard_False),
   myIsGlNormalizeEnabled (Standard_False),
-  mySpriteTexUnit (Graphic3d_TextureUnit_0),
+  mySpriteTexUnit (Graphic3d_TextureUnit_PointSprite),
   myHasRayTracing (Standard_False),
   myHasRayTracingTextures (Standard_False),
   myHasRayTracingAdaptiveSampling (Standard_False),
   myHasRayTracingAdaptiveSamplingAtomic (Standard_False),
   myHasPBR (Standard_False),
-  myPBREnvLUTTexUnit       (Graphic3d_TextureUnit_0),
-  myPBRDiffIBLMapSHTexUnit (Graphic3d_TextureUnit_0),
-  myPBRSpecIBLMapTexUnit   (Graphic3d_TextureUnit_0),
+  myPBREnvLUTTexUnit       (Graphic3d_TextureUnit_PbrEnvironmentLUT),
+  myPBRDiffIBLMapSHTexUnit (Graphic3d_TextureUnit_PbrIblDiffuseSH),
+  myPBRSpecIBLMapTexUnit   (Graphic3d_TextureUnit_PbrIblSpecular),
   myFrameStats (new OpenGl_FrameStats()),
+  myActiveMockTextures (0),
 #if !defined(GL_ES_VERSION_2_0)
   myPointSpriteOrig (GL_UPPER_LEFT),
   myRenderMode (GL_RENDER),
@@ -307,6 +308,18 @@ OpenGl_Context::~OpenGl_Context()
   myDefaultVao = 0;
 #endif
 
+  // release mock textures
+  if (!myTextureRgbaBlack.IsNull())
+  {
+    myTextureRgbaBlack->Release (this);
+    myTextureRgbaBlack.Nullify();
+  }
+  if (!myTextureRgbaWhite.IsNull())
+  {
+    myTextureRgbaWhite->Release (this);
+    myTextureRgbaWhite.Nullify();
+  }
+
   // release default FBO
   if (!myDefaultFbo.IsNull())
   {
@@ -1651,7 +1664,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &myMaxTexCombined);
   }
   mySpriteTexUnit = myMaxTexCombined >= 2
-                  ? Graphic3d_TextureUnit_1
+                  ? Graphic3d_TextureUnit_PointSprite
                   : Graphic3d_TextureUnit_0;
 
   GLint aMaxVPortSize[2] = {0, 0};
@@ -2954,9 +2967,9 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
              );
   if (myHasPBR)
   {
-    myPBREnvLUTTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined - 3);
-    myPBRDiffIBLMapSHTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined - 2);
-    myPBRSpecIBLMapTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined - 1);
+    myPBREnvLUTTexUnit       = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrEnvironmentLUT);
+    myPBRDiffIBLMapSHTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblDiffuseSH);
+    myPBRSpecIBLMapTexUnit   = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblSpecular);
   }
 }
 
@@ -3369,104 +3382,149 @@ void OpenGl_Context::ReleaseDelayed()
 // function : BindTextures
 // purpose  :
 // =======================================================================
-Handle(OpenGl_TextureSet) OpenGl_Context::BindTextures (const Handle(OpenGl_TextureSet)& theTextures)
+Handle(OpenGl_TextureSet) OpenGl_Context::BindTextures (const Handle(OpenGl_TextureSet)& theTextures,
+                                                        const Handle(OpenGl_ShaderProgram)& theProgram)
 {
-  if (myActiveTextures == theTextures)
-  {
-    return myActiveTextures;
+  const Standard_Integer aTextureSetBits = !theTextures.IsNull() ? theTextures->TextureSetBits() : 0;
+  const Standard_Integer aProgramBits    = !theProgram.IsNull() ? theProgram->TextureSetBits() : 0;
+  Standard_Integer aMissingBits = aProgramBits & ~aTextureSetBits;
+  if (aMissingBits != 0
+   && myTextureRgbaBlack.IsNull())
+  {
+    // allocate mock textures
+    myTextureRgbaBlack = new OpenGl_Texture();
+    myTextureRgbaWhite = new OpenGl_Texture();
+    Image_PixMap anImage;
+    anImage.InitZero (Image_Format_RGBA, 2, 2, 0, (Standard_Byte )0);
+    if (!myTextureRgbaBlack->Init (this, OpenGl_TextureFormat::Create<GLubyte, 4>(), Graphic3d_Vec2i (2, 2), Graphic3d_TOT_2D, &anImage))
+    {
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+                    "Error: unable to create unit mock PBR texture map.");
+    }
+    anImage.InitZero (Image_Format_RGBA, 2, 2, 0, (Standard_Byte )255);
+    if (!myTextureRgbaWhite->Init (this, OpenGl_TextureFormat::Create<GLubyte, 4>(), Graphic3d_Vec2i (2, 2), Graphic3d_TOT_2D, &anImage))
+    {
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+                    "Error: unable to create normal mock PBR texture map.");
+    }
   }
 
-  Handle(OpenGl_Context) aThisCtx (this);
-  OpenGl_TextureSet::Iterator aTextureIterOld (myActiveTextures), aTextureIterNew (theTextures);
-  for (;;)
+  Handle(OpenGl_TextureSet) anOldTextures = myActiveTextures;
+  if (myActiveTextures != theTextures)
   {
-    if (!aTextureIterNew.More())
+    Handle(OpenGl_Context) aThisCtx (this);
+    OpenGl_TextureSet::Iterator aTextureIterOld (myActiveTextures), aTextureIterNew (theTextures);
+    for (;;)
     {
-      for (; aTextureIterOld.More(); aTextureIterOld.Next())
+      if (!aTextureIterNew.More())
       {
-        if (const Handle(OpenGl_Texture)& aTextureOld = aTextureIterOld.Value())
+        for (; aTextureIterOld.More(); aTextureIterOld.Next())
         {
-          aTextureOld->Unbind(aThisCtx);
-        #if !defined(GL_ES_VERSION_2_0)
-          if (core11 != NULL)
+          if (const Handle(OpenGl_Texture)& aTextureOld = aTextureIterOld.Value())
           {
-            OpenGl_Sampler::resetGlobalTextureParams (aThisCtx, *aTextureOld, aTextureOld->Sampler()->Parameters());
+            aTextureOld->Unbind (aThisCtx, aTextureIterOld.Unit());
+          #if !defined(GL_ES_VERSION_2_0)
+            if (core11 != NULL)
+            {
+              OpenGl_Sampler::resetGlobalTextureParams (aThisCtx, *aTextureOld, aTextureOld->Sampler()->Parameters());
+            }
+          #endif
           }
-        #endif
         }
+        break;
       }
-      break;
-    }
 
-    const Handle(OpenGl_Texture)& aTextureNew = aTextureIterNew.Value();
-    if (aTextureIterOld.More())
-    {
-      const Handle(OpenGl_Texture)& aTextureOld = aTextureIterOld.Value();
-      if (aTextureNew == aTextureOld)
+      const Handle(OpenGl_Texture)& aTextureNew = aTextureIterNew.Value();
+      if (aTextureIterOld.More())
       {
-        aTextureIterNew.Next();
-        aTextureIterOld.Next();
-        continue;
-      }
-      else if (aTextureNew.IsNull()
-           || !aTextureNew->IsValid())
-      {
-        if (!aTextureOld.IsNull())
+        const Handle(OpenGl_Texture)& aTextureOld = aTextureIterOld.Value();
+        if (aTextureNew == aTextureOld
+         && aTextureIterNew.Unit() == aTextureIterOld.Unit())
         {
-          aTextureOld->Unbind(aThisCtx);
-        #if !defined(GL_ES_VERSION_2_0)
-          if (core11 != NULL)
+          aTextureIterNew.Next();
+          aTextureIterOld.Next();
+          continue;
+        }
+        else if (aTextureNew.IsNull()
+             || !aTextureNew->IsValid())
+        {
+          if (!aTextureOld.IsNull())
           {
-            OpenGl_Sampler::resetGlobalTextureParams (aThisCtx, *aTextureOld, aTextureOld->Sampler()->Parameters());
+            aTextureOld->Unbind (aThisCtx, aTextureIterOld.Unit());
+          #if !defined(GL_ES_VERSION_2_0)
+            if (core11 != NULL)
+            {
+              OpenGl_Sampler::resetGlobalTextureParams (aThisCtx, *aTextureOld, aTextureOld->Sampler()->Parameters());
+            }
+          #endif
           }
-        #endif
+
+          aTextureIterNew.Next();
+          aTextureIterOld.Next();
+          continue;
         }
 
-        aTextureIterNew.Next();
         aTextureIterOld.Next();
+      }
+      if (aTextureNew.IsNull())
+      {
+        aTextureIterNew.Next();
         continue;
       }
 
-      aTextureIterOld.Next();
-    }
-    if (aTextureNew.IsNull())
-    {
-      aTextureIterNew.Next();
-      continue;
-    }
-
-    const Graphic3d_TextureUnit aTexUnit = aTextureNew->Sampler()->Parameters()->TextureUnit();
-    if (aTexUnit >= myMaxTexCombined)
-    {
-      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
-                   TCollection_AsciiString("Texture unit ") + aTexUnit + " for " + aTextureNew->ResourceId() + " exceeds hardware limit " + myMaxTexCombined);
-      aTextureIterNew.Next();
-      continue;
-    }
+      const Graphic3d_TextureUnit aTexUnit = aTextureIterNew.Unit();
+      if (aTexUnit >= myMaxTexCombined)
+      {
+        PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                     TCollection_AsciiString("Texture unit ") + aTexUnit + " for " + aTextureNew->ResourceId() + " exceeds hardware limit " + myMaxTexCombined);
+        aTextureIterNew.Next();
+        continue;
+      }
 
-    aTextureNew->Bind (aThisCtx);
-    if (aTextureNew->Sampler()->ToUpdateParameters())
-    {
-      if (aTextureNew->Sampler()->IsImmutable())
+      aTextureNew->Bind (aThisCtx, aTexUnit);
+      if (aTextureNew->Sampler()->ToUpdateParameters())
       {
-        aTextureNew->Sampler()->Init (aThisCtx, *aTextureNew);
+        if (aTextureNew->Sampler()->IsImmutable())
+        {
+          aTextureNew->Sampler()->Init (aThisCtx, *aTextureNew);
+        }
+        else
+        {
+          OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->HasMipmaps());
+        }
       }
-      else
+    #if !defined(GL_ES_VERSION_2_0)
+      if (core11 != NULL)
       {
-        OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->HasMipmaps());
+        OpenGl_Sampler::applyGlobalTextureParams (aThisCtx, *aTextureNew, aTextureNew->Sampler()->Parameters());
       }
+    #endif
+      aTextureIterNew.Next();
     }
-  #if !defined(GL_ES_VERSION_2_0)
-    if (core11 != NULL)
+    myActiveTextures = theTextures;
+  }
+
+  if (myActiveMockTextures != aMissingBits)
+  {
+    myActiveMockTextures = aMissingBits;
+    for (Standard_Integer aBitIter = 0; aMissingBits != 0; ++aBitIter)
     {
-      OpenGl_Sampler::applyGlobalTextureParams (aThisCtx, *aTextureNew, aTextureNew->Sampler()->Parameters());
+      Standard_Integer aUnitMask = 1 << aBitIter;
+      if ((aUnitMask & aMissingBits) != 0)
+      {
+        aMissingBits = aMissingBits & ~aUnitMask;
+        if (aBitIter == Graphic3d_TextureUnit_Normal)
+        {
+          myTextureRgbaBlack->Bind (this, static_cast<Graphic3d_TextureUnit>(aBitIter));
+        }
+        else
+        {
+          myTextureRgbaWhite->Bind (this, static_cast<Graphic3d_TextureUnit>(aBitIter));
+        }
+      }
     }
-  #endif
-    aTextureIterNew.Next();
   }
 
-  Handle(OpenGl_TextureSet) anOldTextures = myActiveTextures;
-  myActiveTextures = theTextures;
   return anOldTextures;
 }
 
index a7c4215..e757526 100644 (file)
@@ -502,7 +502,7 @@ public:
   //! @return value for GL_MAX_TEXTURE_UNITS
   Standard_Integer MaxTextureUnitsFFP() const { return myMaxTexUnitsFFP; }
 
-  //! @return texture unit to be used for sprites
+  //! Return texture unit to be used for sprites (Graphic3d_TextureUnit_PointSprite by default).
   Graphic3d_TextureUnit SpriteTextureUnit() const { return mySpriteTexUnit; }
 
   //! @return value for GL_MAX_SAMPLES
@@ -803,9 +803,20 @@ public: //! @name methods to alter or retrieve current state
   //! @return active textures
   const Handle(OpenGl_TextureSet)& ActiveTextures() const { return myActiveTextures; }
 
-  //! Bind specified texture set to current context,
-  //! or unbind previous one when NULL specified.
-  Standard_EXPORT Handle(OpenGl_TextureSet) BindTextures (const Handle(OpenGl_TextureSet)& theTextures);
+  //! Bind specified texture set to current context taking into account active GLSL program.
+  Standard_DEPRECATED("BindTextures() with explicit GLSL program should be used instead")
+  Handle(OpenGl_TextureSet) BindTextures (const Handle(OpenGl_TextureSet)& theTextures)
+  {
+    return BindTextures (theTextures, myActiveProgram);
+  }
+
+  //! Bind specified texture set to current context, or unbind previous one when NULL specified.
+  //! @param theTextures [in] texture set to bind
+  //! @param theProgram  [in] program attributes; when not NULL,
+  //!                         mock textures will be bound to texture units expected by GLSL program, but undefined by texture set
+  //! @return previous texture set
+  Standard_EXPORT Handle(OpenGl_TextureSet) BindTextures (const Handle(OpenGl_TextureSet)& theTextures,
+                                                          const Handle(OpenGl_ShaderProgram)& theProgram);
 
   //! @return active GLSL program
   const Handle(OpenGl_ShaderProgram)& ActiveProgram() const
@@ -1076,7 +1087,7 @@ private: // context info
   Standard_Boolean myIsStereoBuffers;      //!< context supports stereo buffering
   Standard_Boolean myIsGlNormalizeEnabled; //!< GL_NORMALIZE flag
                                            //!< Used to tell OpenGl that normals should be normalized
-  Graphic3d_TextureUnit mySpriteTexUnit;   //!< texture unit for point sprite texture
+  Graphic3d_TextureUnit mySpriteTexUnit;   //!< sampler2D occSamplerPointSprite, texture unit for point sprite texture
 
   Standard_Boolean myHasRayTracing;                 //! indicates whether ray tracing mode is supported
   Standard_Boolean myHasRayTracingTextures;         //! indicates whether textures in ray tracing mode are supported
@@ -1084,10 +1095,10 @@ private: // context info
   Standard_Boolean myHasRayTracingAdaptiveSamplingAtomic; //! indicates whether atomic adaptive screen sampling in ray tracing mode is supported
 
   Standard_Boolean myHasPBR;                      //!< indicates whether PBR shading model is supported
-  Graphic3d_TextureUnit myPBREnvLUTTexUnit;       //!< texture unit where environment lookup table is expected to be binded (0 if PBR is not supported)
-  Graphic3d_TextureUnit myPBRDiffIBLMapSHTexUnit; //!< texture unit where diffuse (irradiance) IBL map's spherical harmonics coefficients is expected to  be binded
+  Graphic3d_TextureUnit myPBREnvLUTTexUnit;       //!< sampler2D occEnvLUT, texture unit where environment lookup table is expected to be binded (0 if PBR is not supported)
+  Graphic3d_TextureUnit myPBRDiffIBLMapSHTexUnit; //!< sampler2D occDiffIBLMapSHCoeffs, texture unit where diffuse (irradiance) IBL map's spherical harmonics coefficients is expected to  be binded
                                                   //!  (0 if PBR is not supported)
-  Graphic3d_TextureUnit myPBRSpecIBLMapTexUnit;   //!< texture unit where specular IBL map is expected to  be binded (0 if PBR is not supported)
+  Graphic3d_TextureUnit myPBRSpecIBLMapTexUnit;   //!< samplerCube occSpecIBLMap, texture unit where specular IBL map is expected to  be binded (0 if PBR is not supported)
 
   Handle(OpenGl_ShaderManager) myShaderManager; //! support object for managing shader programs
 
@@ -1097,8 +1108,11 @@ private: //! @name fields tracking current state
   Handle(OpenGl_ShaderProgram)  myActiveProgram;   //!< currently active GLSL program
   Handle(OpenGl_TextureSet)     myActiveTextures;  //!< currently bound textures
                                                    //!< currently active sampler objects
+  Standard_Integer              myActiveMockTextures; //!< currently active mock sampler objects
   Handle(OpenGl_FrameBuffer)    myDefaultFbo;      //!< default Frame Buffer Object
   Handle(OpenGl_LineAttributes) myHatchStyles;     //!< resource holding predefined hatch styles patterns
+  Handle(OpenGl_Texture)        myTextureRgbaBlack;//!< mock black texture returning (0, 0, 0, 0)
+  Handle(OpenGl_Texture)        myTextureRgbaWhite;//!< mock white texture returning (1, 1, 1, 1)
   Standard_Integer              myViewport[4];     //!< current viewport
   Standard_Integer              myViewportVirt[4]; //!< virtual viewport
   Standard_Integer              myPointSpriteOrig; //!< GL_POINT_SPRITE_COORD_ORIGIN state (GL_UPPER_LEFT by default)
index b312644..f639a58 100644 (file)
@@ -932,7 +932,7 @@ void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)&   theW
       // Bind full screen quad buffer and framebuffer resources.
       aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
 
-      const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+      const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
 
       theOitAccumFbo->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_0);
       theOitAccumFbo->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_1);
@@ -949,7 +949,7 @@ void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)&   theW
 
       if (!aTextureBack.IsNull())
       {
-        aCtx->BindTextures (aTextureBack);
+        aCtx->BindTextures (aTextureBack, Handle(OpenGl_ShaderProgram)());
       }
     }
     else
index 97a6f39..9bb3274 100644 (file)
@@ -769,12 +769,10 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
     return;
   }
 
-  const OpenGl_Aspects* anAspectFace = theWorkspace->ApplyAspects();
+  const OpenGl_Aspects* anAspectFace = theWorkspace->Aspects();
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
 
-  const bool toEnableEnvMap = !aCtx->ActiveTextures().IsNull()
-                            && aCtx->ActiveTextures() == theWorkspace->EnvironmentTexture();
-  bool toDrawArray = true;
+  bool toDrawArray = true, toSetLinePolygMode = false;
   int toDrawInteriorEdges = 0; // 0 - no edges, 1 - glsl edges, 2 - polygonMode
   if (myIsFillType)
   {
@@ -797,7 +795,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
           }
           else
           {
-            aCtx->SetPolygonMode (GL_LINE);
+            toSetLinePolygMode = true;
           }
         }
       }
@@ -843,6 +841,10 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
   }
 
   Graphic3d_TypeOfShadingModel aShadingModel = Graphic3d_TOSM_UNLIT;
+  anAspectFace = theWorkspace->ApplyAspects (false); // do not bind textures before binding the program
+  const Handle(OpenGl_TextureSet)& aTextureSet = theWorkspace->TextureSet();
+  const bool toEnableEnvMap = !aTextureSet.IsNull()
+                            && aTextureSet == theWorkspace->EnvironmentTexture();
   if (toDrawArray)
   {
     const bool hasColorAttrib = !myVboAttribs.IsNull()
@@ -855,7 +857,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
       case GL_POINTS:
       {
         aShadingModel = aCtx->ShaderManager()->ChooseMarkerShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
-        aCtx->ShaderManager()->BindMarkerProgram (aCtx->ActiveTextures(),
+        aCtx->ShaderManager()->BindMarkerProgram (aTextureSet,
                                                   aShadingModel, Graphic3d_AlphaMode_Opaque,
                                                   hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
         break;
@@ -875,7 +877,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
       default:
       {
         aShadingModel = aCtx->ShaderManager()->ChooseFaceShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
-        aCtx->ShaderManager()->BindFaceProgram (aCtx->ActiveTextures(),
+        aCtx->ShaderManager()->BindFaceProgram (aTextureSet,
                                                 aShadingModel,
                                                 aCtx->ShaderManager()->MaterialState().HasAlphaCutoff() ? Graphic3d_AlphaMode_Mask : Graphic3d_AlphaMode_Opaque,
                                                 toDrawInteriorEdges == 1 ? anAspectFace->Aspect()->InteriorStyle() : Aspect_IS_SOLID,
@@ -887,6 +889,14 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
         {
           aCtx->ShaderManager()->PushInteriorState (aCtx->ActiveProgram(), anAspectFace->Aspect());
         }
+      #if !defined (GL_ES_VERSION_2_0)
+        else if (toSetLinePolygMode)
+        {
+          aCtx->SetPolygonMode (GL_LINE);
+        }
+      #else
+        (void )toSetLinePolygMode;
+      #endif
         break;
       }
     }
@@ -907,12 +917,16 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
     }
   #endif
 
-    if (!aCtx->ActiveTextures().IsNull()
-     && !aCtx->ActiveTextures()->IsEmpty()
-     && !aCtx->ActiveTextures()->First().IsNull()
+    // bind textures after GLSL program to set mock textures to slots used by program
+    aCtx->BindTextures (aTextureSet, aCtx->ActiveProgram());
+    if (!aTextureSet.IsNull()
+     && !aTextureSet->IsEmpty()
      && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
     {
-      aCtx->SetTextureMatrix (aCtx->ActiveTextures()->First()->Sampler()->Parameters());
+      if (const Handle(OpenGl_Texture)& aFirstTexture = aTextureSet->First())
+      {
+        aCtx->SetTextureMatrix (aFirstTexture->Sampler()->Parameters());
+      }
     }
     aCtx->SetSampleAlphaToCoverage (aCtx->ShaderManager()->MaterialState().HasAlphaCutoff());
 
index 8c0434b..0c1eabe 100644 (file)
 enum OpenGl_ProgramOptions
 {
   OpenGl_PO_VertColor       = 0x0001, //!< per-vertex color
-  OpenGl_PO_TextureRGB      = 0x0002, //!< handle RGB   texturing
-  OpenGl_PO_PointSimple     = 0x0004, //!< point marker without sprite
-  OpenGl_PO_PointSprite     = 0x0008, //!< point sprite with RGB image
+  OpenGl_PO_TextureRGB      = 0x0002, //!< handle RGB texturing
+  OpenGl_PO_TextureEnv      = 0x0004, //!< handle environment map (obsolete, to be removed)
+  OpenGl_PO_TextureNormal   = OpenGl_PO_TextureRGB|OpenGl_PO_TextureEnv, //!< extended texture set (with normal map)
+  OpenGl_PO_PointSimple     = 0x0008, //!< point marker without sprite
+  OpenGl_PO_PointSprite     = 0x0010, //!< point sprite with RGB image
   OpenGl_PO_PointSpriteA    = OpenGl_PO_PointSimple|OpenGl_PO_PointSprite, //!< point sprite with Alpha image
-  OpenGl_PO_TextureEnv      = 0x0010, //!< handle environment map
   OpenGl_PO_StippleLine     = 0x0020, //!< stipple line
   OpenGl_PO_ClipPlanes1     = 0x0040, //!< handle 1 clipping plane
   OpenGl_PO_ClipPlanes2     = 0x0080, //!< handle 2 clipping planes
@@ -40,7 +41,7 @@ enum OpenGl_ProgramOptions
   //
   OpenGl_PO_NB              = 0x1000, //!< overall number of combinations
   OpenGl_PO_IsPoint         = OpenGl_PO_PointSimple|OpenGl_PO_PointSprite|OpenGl_PO_PointSpriteA,
-  OpenGl_PO_HasTextures     = OpenGl_PO_TextureRGB,
+  OpenGl_PO_HasTextures     = OpenGl_PO_TextureRGB|OpenGl_PO_TextureEnv,
   OpenGl_PO_NeedsGeomShader = OpenGl_PO_MeshEdges,
 };
 
index dcb2080..ee435d0 100644 (file)
@@ -96,6 +96,7 @@ const char THE_FUNC_PBR_lightDef[] =
   EOL"vec3  DirectLighting;" //!< Accumulator of direct lighting from light sources
   EOL"vec4  BaseColor;"      //!< Base color (albedo) of material for PBR
   EOL"float Metallic;"       //!< Metallic coefficient of material
+  EOL"float NormalizedRoughness;" //!< Normalized roughness coefficient of material
   EOL"float Roughness;"      //!< Roughness coefficient of material
   EOL"vec3  Emission;"       //!< Light intensity emitted by material
   EOL"float IOR;";           //!< Material's index of refraction
@@ -1771,7 +1772,8 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr
 {
   int aBits = theBits;
   const bool toUseDerivates = theUsesDerivates
-                          || (theBits & OpenGl_PO_StippleLine) != 0;
+                          || (theBits & OpenGl_PO_StippleLine) != 0
+                          || (theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureNormal;
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core32 != NULL)
   {
@@ -1971,9 +1973,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
         aSrcFragGetColor =
           EOL"vec4 getColor(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord "); }";
       }
-      else if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+      else if ((theBits & OpenGl_PO_TextureRGB) != 0
             && (theBits & OpenGl_PO_VertColor) == 0)
       {
+        aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
         aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
         aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
         aSrcVertExtraMain +=
@@ -2000,9 +2003,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     }
     else
     {
-      if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+      if ((theBits & OpenGl_PO_TextureRGB) != 0
        && (theBits & OpenGl_PO_VertColor) == 0)
       {
+        aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
         aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
         aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
         aSrcVertExtraMain +=
@@ -2019,32 +2023,33 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
   }
   else
   {
-    if ((theBits & OpenGl_PO_TextureRGB) != 0 || (theBits & OpenGl_PO_TextureEnv) != 0)
+    if ((theBits & OpenGl_PO_HasTextures) != 0)
     {
       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
-    }
 
-    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
-    {
-      aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
+      if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureEnv)
+      {
+        aSrcVertExtraFunc = THE_FUNC_transformNormal_view;
 
-      aSrcFragGetColor =
-        EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w); }";
-    }
-    else if ((theBits & OpenGl_PO_TextureEnv) != 0)
-    {
-      aSrcVertExtraFunc = THE_FUNC_transformNormal_view;
+        aSrcVertExtraMain +=
+          EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
+          EOL"  vec3 aNormal   = transformNormal (occNormal);"
+          EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
+          EOL"  aReflect.z += 1.0;"
+          EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
 
-      aSrcVertExtraMain +=
-        EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
-        EOL"  vec3 aNormal   = transformNormal (occNormal);"
-        EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
-        EOL"  aReflect.z += 1.0;"
-        EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
+        aSrcFragGetColor =
+          EOL"vec4 getColor(void) { return occTexture2D (occSamplerBaseColor, TexCoord.st); }";
+      }
+      else
+      {
+        aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
+        aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
-      aSrcFragGetColor =
-        EOL"vec4 getColor(void) { return occTexture2D (occSamplerBaseColor, TexCoord.st); }";
+        aSrcFragGetColor =
+          EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w); }";
+      }
     }
   }
   if ((theBits & OpenGl_PO_VertColor) != 0)
@@ -2218,7 +2223,8 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TColl
 // =======================================================================
 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
                                                                   Standard_Boolean  theHasVertColor,
-                                                                  Standard_Boolean  theIsPBR)
+                                                                  Standard_Boolean  theIsPBR,
+                                                                  Standard_Boolean  theHasEmissive)
 {
   TCollection_AsciiString aLightsFunc, aLightsLoop;
   theNbLights = 0;
@@ -2353,12 +2359,12 @@ TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integ
     + EOL"  vec4 aMatAmbient  = " + aGetMatAmbient
     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
     + EOL"  vec4 aMatSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
-      EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
-      EOL"  vec3 aColor = Ambient  * aMatAmbient.rgb"
-      EOL"              + Diffuse  * aMatDiffuse.rgb"
-      EOL"              + Specular * aMatSpecular.rgb"
-      EOL"                         + aMatEmission.rgb;"
-      EOL"  return vec4 (aColor, aMatDiffuse.a);"
+      EOL"  vec3 aColor = Ambient * aMatAmbient.rgb + Diffuse * aMatDiffuse.rgb + Specular * aMatSpecular.rgb;"
+      EOL"  occTextureOcclusion(aColor, TexCoord.st);"
+    + (theHasEmissive
+    ? EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
+      EOL"  aColor += aMatEmission.rgb;" : "")
+    + EOL"  return vec4 (aColor, aMatDiffuse.a);"
       EOL"}";
   }
   else
@@ -2373,26 +2379,27 @@ TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integ
       EOL"                      in bool theIsFront)"
       EOL"{"
       EOL"  DirectLighting = vec3(0.0);"
-      EOL"  BaseColor = " + (theHasVertColor ? "getVertColor();" : "getBaseColor (theIsFront);")
-    + EOL"  Metallic  = theIsFront ? occPBRFrontMaterial_Metallic()  : occPBRBackMaterial_Metallic();"
-      EOL"  Roughness = theIsFront ? occPBRFrontMaterial_Roughness() : occPBRBackMaterial_Roughness();"
-      EOL"  IOR       = theIsFront ? occPBRFrontMaterial_IOR()       : occPBRBackMaterial_IOR();"
-      EOL"  Emission  = theIsFront ? occPBRFrontMaterial_Emission()  : occPBRBackMaterial_Emission();"
+      EOL"  BaseColor = " + (theHasVertColor ? "getVertColor();" : "occTextureColor(occPBRMaterial_Color (theIsFront), TexCoord.st);")
+    + EOL"  Emission            = occTextureEmissive(occPBRMaterial_Emission (theIsFront), TexCoord.st);"
+      EOL"  Metallic            = occTextureMetallic(occPBRMaterial_Metallic (theIsFront), TexCoord.st);"
+      EOL"  NormalizedRoughness = occTextureRoughness(occPBRMaterial_NormalizedRoughness (theIsFront), TexCoord.st);"
+      EOL"  Roughness = occRoughness (NormalizedRoughness);"
+      EOL"  IOR       = occPBRMaterial_IOR (theIsFront);"
       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
     + aLightsLoop
     + EOL"  vec3 aColor = DirectLighting;"
       EOL"  vec3 anIndirectLightingSpec = occPBRFresnel (BaseColor.rgb, Metallic, IOR);"
-      EOL"  Roughness = theIsFront ? occPBRFrontMaterial_NormalizedRoughness() : occPBRBackMaterial_NormalizedRoughness();"
-      EOL"  vec2 aCoeff = occTexture2D (occEnvLUT, vec2(abs(dot(theView, theNormal)), Roughness)).xy;"
+      EOL"  vec2 aCoeff = occTexture2D (occEnvLUT, vec2(abs(dot(theView, theNormal)), NormalizedRoughness)).xy;"
       EOL"  anIndirectLightingSpec *= aCoeff.x;"
       EOL"  anIndirectLightingSpec += aCoeff.y;"
-      EOL"  anIndirectLightingSpec *= occTextureCubeLod (occSpecIBLMap, -reflect (theView, theNormal), Roughness * float (occNbSpecIBLLevels - 1)).rgb;"
-      EOL"  vec3 aRefractionCoeff = 1.0 - occPBRFresnel (BaseColor.rgb, Metallic, Roughness, IOR, abs(dot(theView, theNormal)));"
+      EOL"  anIndirectLightingSpec *= occTextureCubeLod (occSpecIBLMap, -reflect (theView, theNormal), NormalizedRoughness * float (occNbSpecIBLLevels - 1)).rgb;"
+      EOL"  vec3 aRefractionCoeff = 1.0 - occPBRFresnel (BaseColor.rgb, Metallic, NormalizedRoughness, IOR, abs(dot(theView, theNormal)));"
       EOL"  aRefractionCoeff *= (1.0 - Metallic);"
       EOL"  vec3 anIndirectLightingDiff = aRefractionCoeff * BaseColor.rgb * BaseColor.a;"
       EOL"  anIndirectLightingDiff *= occDiffIBLMap (theNormal).rgb;"
       EOL"  aColor += occLightAmbient.rgb * (anIndirectLightingDiff + anIndirectLightingSpec);"
       EOL"  aColor += Emission;"
+      EOL"  occTextureOcclusion(aColor, TexCoord.st);"
       EOL"  return vec4 (aColor, mix(1.0, BaseColor.a, aRefractionCoeff.x));"
       EOL"}";
   }
@@ -2431,17 +2438,19 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
     }
 
-    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+    if ((theBits & OpenGl_PO_TextureRGB) != 0
      && (theBits & OpenGl_PO_VertColor) == 0)
     {
+      aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
       aSrcVertColor = EOL"vec4 getVertColor(void) { return occTexture2D (occSamplerBaseColor, occTexCoord.xy); }";
     }
   }
   else
   {
-    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
+    if ((theBits & OpenGl_PO_TextureRGB) != 0)
     {
+      aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
@@ -2499,7 +2508,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 BackColor",  Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
 
   Standard_Integer aNbLights = 0;
-  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcVertColor.IsEmpty(), false);
+  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcVertColor.IsEmpty(), false, true);
   aSrcVert = TCollection_AsciiString()
     + THE_FUNC_transformNormal_view
     + EOL
@@ -2584,13 +2593,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   aProgramSrc->SetPBR (theIsPBR);
 
   TCollection_AsciiString aSrcVert, aSrcVertExtraFunc, aSrcVertExtraMain;
-  TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
+  TCollection_AsciiString aSrcFrag, aSrcFragExtraFunc, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
   TCollection_AsciiString aSrcFragGetColor = TCollection_AsciiString() + EOL"vec4 getColor(void) { return " + aPhongCompLight +  "; }";
-  TCollection_AsciiString aSrcFragPBRGetBaseColor = TCollection_AsciiString() +
-    EOL"vec4 getBaseColor(in bool theIsFront)"
-    EOL"{"
-    EOL"  return theIsFront ? occPBRFrontMaterial_Color() : occPBRBackMaterial_Color();"
-    EOL"}";
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
   if ((theBits & OpenGl_PO_IsPoint) != 0)
   {
@@ -2612,9 +2616,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
       aSrcFragGetColor = pointSpriteShadingSrc (aPhongCompLight, theBits);
     }
 
-    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+    if ((theBits & OpenGl_PO_TextureRGB) != 0
      && (theBits & OpenGl_PO_VertColor) == 0)
     {
+      aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
 
@@ -2624,30 +2629,44 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   }
   else
   {
-    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
+    if ((theBits & OpenGl_PO_TextureRGB) != 0)
     {
       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
+      Standard_Integer aTextureBits = Graphic3d_TextureSetBits_BaseColor | Graphic3d_TextureSetBits_Occlusion | Graphic3d_TextureSetBits_Emissive;
       if (!theIsPBR)
       {
         aSrcFragGetColor = TCollection_AsciiString() +
           EOL"vec4 getColor(void)"
           EOL"{"
+          EOL"  vec2 aTexUV = TexCoord.st / TexCoord.w;"
           EOL"  vec4 aColor = " + aPhongCompLight + ";"
-          EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
+          EOL"  aColor *= occTexture2D(occSamplerBaseColor, aTexUV);"
+          EOL"  vec3 anEmission = occTextureEmissive((gl_FrontFacing ? occFrontMaterial_Emission() : occBackMaterial_Emission()).rgb, aTexUV);"
+          EOL"  aColor.rgb += anEmission;"
+          EOL"  return aColor;"
           EOL"}";
       }
       else
       {
-        aSrcFragPBRGetBaseColor = TCollection_AsciiString() +
-          EOL"vec4 getBaseColor (in bool theIsFront)"
-          EOL"{"
-          EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) *"
-          EOL"         (theIsFront ? occPBRFrontMaterial_Color() : occPBRBackMaterial_Color());"
-          EOL"}";
+        aTextureBits |= Graphic3d_TextureSetBits_MetallicRoughness;
+      }
+      if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureNormal
+       && !isFlatNormal)
+      {
+        if (myContext->hasFlatShading != OpenGl_FeatureNotAvailable)
+        {
+          aTextureBits |= Graphic3d_TextureSetBits_Normal;
+        }
+        else
+        {
+          myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                                  "Warning: ignoring Normal Map texture due to hardware capabilities");
+        }
       }
+      aProgramSrc->SetTextureSetBits (aTextureBits);
     }
   }
 
@@ -2696,9 +2715,37 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   }
   else
   {
-    aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 Normal", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
-    aSrcVertExtraFunc += theIsPBR ? THE_FUNC_transformNormal_world : THE_FUNC_transformNormal_view;
-    aSrcVertExtraMain += EOL"  Normal = transformNormal (occNormal);";
+    aStageInOuts.Append(OpenGl_ShaderObject::ShaderVariable("vec3 vNormal", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+    aSrcVertExtraFunc += THE_FUNC_transformNormal_world;
+    aSrcVertExtraMain += EOL"  vNormal = transformNormal (occNormal);";
+    aSrcFragExtraFunc += EOL"  vec3 Normal = vNormal;";
+
+    if ((theBits & OpenGl_PO_IsPoint) == 0
+     && (theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureNormal
+     && myContext->hasFlatShading != OpenGl_FeatureNotAvailable)
+    {
+      // apply normal map texture
+      aSrcFragExtraMain +=
+        EOL"#if defined(THE_HAS_TEXTURE_NORMAL)"
+        EOL"  vec4 aMapNormalValue = occTextureNormal(TexCoord.st / TexCoord.w);"
+        EOL"  if (aMapNormalValue.w > 0.5)"
+        EOL"  {"
+        EOL"    aMapNormalValue.xyz = normalize (aMapNormalValue.xyz * 2.0 - vec3(1.0));"
+        EOL"    mat2 aDeltaUVMatrix = mat2 (dFdx(TexCoord.st / TexCoord.w), dFdy(TexCoord.st / TexCoord.w));"
+        EOL"    aDeltaUVMatrix = mat2 (aDeltaUVMatrix[1][1], -aDeltaUVMatrix[0][1], -aDeltaUVMatrix[1][0], aDeltaUVMatrix[0][0]);"
+        EOL"    mat2x3 aDeltaVectorMatrix = mat2x3 (dFdx (PositionWorld.xyz), dFdy (PositionWorld.xyz));"
+        EOL"    aDeltaVectorMatrix = aDeltaVectorMatrix * aDeltaUVMatrix;"
+        EOL"    aDeltaVectorMatrix[0] = aDeltaVectorMatrix[0] - dot(Normal, aDeltaVectorMatrix[0]) * Normal;"
+        EOL"    aDeltaVectorMatrix[1] = aDeltaVectorMatrix[1] - dot(Normal, aDeltaVectorMatrix[1]) * Normal;"
+        EOL"    Normal = mat3 (-normalize(aDeltaVectorMatrix[0]), -normalize(aDeltaVectorMatrix[1]), Normal) * aMapNormalValue.xyz;"
+        EOL"  }"
+        EOL"#endif";
+    }
+    if (!theIsPBR)
+    {
+      aSrcFragExtraMain +=
+        EOL"  Normal = normalize ((occWorldViewMatrixInverseTranspose * vec4 (Normal, 0.0)).xyz);";
+    }
   }
 
   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
@@ -2730,12 +2777,14 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
     : EOL"#define getFinalColor getColor";
 
   Standard_Integer aNbLights = 0;
-  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcFragGetVertColor.IsEmpty(), theIsPBR);
+  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcFragGetVertColor.IsEmpty(), theIsPBR,
+                                                              (theBits & OpenGl_PO_TextureRGB) == 0
+                                                           || (theBits & OpenGl_PO_IsPoint) != 0);
   aSrcFrag = TCollection_AsciiString()
     + EOL
+    + aSrcFragExtraFunc
     + aSrcFragExtraOut
     + aSrcFragGetVertColor
-    + (theIsPBR ? aSrcFragPBRGetBaseColor : "")
     + aLights
     + aSrcFragGetColor
     + EOL
index 793ac51..ea56a48 100644 (file)
@@ -618,6 +618,10 @@ protected:
            && theTextures->HasNonPointSprite())
     {
       aBits |= OpenGl_PO_TextureRGB;
+      if ((theTextures->TextureSetBits() & Graphic3d_TextureSetBits_Normal) != 0)
+      {
+        aBits |= OpenGl_PO_TextureNormal;
+      }
     }
     if (theHasVertColor
      && theInteriorStyle != Aspect_IS_HIDDENLINE)
@@ -637,7 +641,7 @@ protected:
                                                Standard_Integer theBits)
   {
     if (theShadingModel == Graphic3d_TOSM_UNLIT
-     || (theBits & OpenGl_PO_TextureEnv) != 0)
+     || (theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureEnv)
     {
       // If environment map is enabled lighting calculations are
       // not needed (in accordance with default OCCT behavior)
@@ -714,9 +718,11 @@ protected:
   //! @param theNbLights     [out] number of defined light sources
   //! @param theHasVertColor [in]  flag to use getVertColor() instead of Ambient and Diffuse components of active material
   //! @param theIsPBR        [in]  flag to activate PBR pipeline
+  //! @param theHasEmissive  [in]  flag to include emissive
   Standard_EXPORT TCollection_AsciiString stdComputeLighting (Standard_Integer& theNbLights,
                                                               Standard_Boolean  theHasVertColor,
-                                                              Standard_Boolean  theIsPBR);
+                                                              Standard_Boolean  theIsPBR,
+                                                              Standard_Boolean  theHasEmissive = true);
 
   //! Bind specified program to current context and apply state.
   Standard_EXPORT Standard_Boolean bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram);
index 68b3af2..651bb34 100755 (executable)
@@ -171,6 +171,7 @@ OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram
   myNbLightsMax (0),
   myNbClipPlanesMax (0),
   myNbFragOutputs (1),
+  myTextureSetBits (Graphic3d_TextureSetBits_NONE),
   myHasAlphaTest (false),
   myHasWeightOitOutput (false),
   myHasTessShader (false)
@@ -199,6 +200,7 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
   }
   myHasTessShader = (aShaderMask & (Graphic3d_TOS_TESS_CONTROL | Graphic3d_TOS_TESS_EVALUATION)) != 0;
   myNbFragOutputs = !myProxy.IsNull() ? myProxy->NbFragmentOutputs() : 1;
+  myTextureSetBits = Graphic3d_TextureSetBits_NONE;
   myHasAlphaTest  = !myProxy.IsNull() && myProxy->HasAlphaTest();
   myHasWeightOitOutput = !myProxy.IsNull() ? myProxy->HasWeightOitOutput() && myNbFragOutputs >= 2 : 1;
 
@@ -413,10 +415,32 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
     {
       aHeaderConstants += "#define THE_HAS_DEFAULT_SAMPLER\n";
     }
-    if (!myProxy.IsNull()
-      && myProxy->IsPBR())
+    if (!myProxy.IsNull())
     {
-      aHeaderConstants += "#define THE_IS_PBR\n";
+      if (myProxy->IsPBR())
+      {
+        aHeaderConstants += "#define THE_IS_PBR\n";
+      }
+      if ((myProxy->TextureSetBits() & Graphic3d_TextureSetBits_BaseColor) != 0)
+      {
+        aHeaderConstants += "#define THE_HAS_TEXTURE_COLOR\n";
+      }
+      if ((myProxy->TextureSetBits() & Graphic3d_TextureSetBits_Emissive) != 0)
+      {
+        aHeaderConstants += "#define THE_HAS_TEXTURE_EMISSIVE\n";
+      }
+      if ((myProxy->TextureSetBits() & Graphic3d_TextureSetBits_Normal) != 0)
+      {
+        aHeaderConstants += "#define THE_HAS_TEXTURE_NORMAL\n";
+      }
+      if ((myProxy->TextureSetBits() & Graphic3d_TextureSetBits_Occlusion) != 0)
+      {
+        aHeaderConstants += "#define THE_HAS_TEXTURE_OCCLUSION\n";
+      }
+      if ((myProxy->TextureSetBits() & Graphic3d_TextureSetBits_MetallicRoughness) != 0)
+      {
+        aHeaderConstants += "#define THE_HAS_TEXTURE_METALROUGHNESS\n";
+      }
     }
 
     const TCollection_AsciiString aSource = aHeaderVer                     // #version   - header defining GLSL version, should be first
@@ -491,12 +515,35 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
   }
   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerBaseColor"))
   {
+    myTextureSetBits |= Graphic3d_TextureSetBits_BaseColor;
     SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_BaseColor));
   }
   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerPointSprite"))
   {
+    // Graphic3d_TextureUnit_PointSprite
+    //myTextureSetBits |= Graphic3d_TextureSetBits_PointSprite;
     SetUniform (theCtx, aLocSampler, GLint(theCtx->SpriteTextureUnit()));
   }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerMetallicRoughness"))
+  {
+    myTextureSetBits |= Graphic3d_TextureSetBits_MetallicRoughness;
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_MetallicRoughness));
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerEmissive"))
+  {
+    myTextureSetBits |= Graphic3d_TextureSetBits_Emissive;
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_Emissive));
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerOcclusion"))
+  {
+    myTextureSetBits |= Graphic3d_TextureSetBits_Occlusion;
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_Occlusion));
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerNormal"))
+  {
+    myTextureSetBits |= Graphic3d_TextureSetBits_Normal;
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_Normal));
+  }
   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occDiffIBLMapSHCoeffs"))
   {
     SetUniform (theCtx, aLocSampler, GLint(theCtx->PBRDiffIBLMapSHTexUnit()));
index 93252bb..c86f0ec 100755 (executable)
@@ -22,6 +22,7 @@
 
 #include <Graphic3d_ShaderObject.hxx>
 #include <Graphic3d_ShaderProgram.hxx>
+#include <Graphic3d_TextureSetBits.hxx>
 
 #include <OpenGl_Vec.hxx>
 #include <OpenGl_Matrix.hxx>
@@ -294,6 +295,9 @@ public:
   //! Return true if Fragment Shader color should output the weighted OIT coverage; FALSE by default.
   Standard_Boolean HasWeightOitOutput() const { return myHasWeightOitOutput; }
 
+  //! Return texture units declared within the program, @sa Graphic3d_TextureSetBits.
+  Standard_Integer TextureSetBits() const { return myTextureSetBits; }
+
 private:
 
   //! Returns index of last modification of variables of specified state type.
@@ -656,6 +660,7 @@ protected:
   Standard_Integer                myNbLightsMax;   //!< length of array of light sources (THE_MAX_LIGHTS)
   Standard_Integer                myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
   Standard_Integer                myNbFragOutputs; //!< length of array of Fragment Shader outputs (THE_NB_FRAG_OUTPUTS)
+  Standard_Integer                myTextureSetBits;//!< texture units declared within the program, @sa Graphic3d_TextureSetBits
   Standard_Boolean                myHasAlphaTest;  //!< flag indicating that Fragment Shader should perform alpha-test
   Standard_Boolean                myHasWeightOitOutput; //!< flag indicating that Fragment Shader includes weighted OIT coverage
   Standard_Boolean                myHasTessShader; //!< flag indicating that program defines tessellation stage
index 927a4a0..fdc8f36 100644 (file)
@@ -39,7 +39,7 @@ void OpenGl_Structure::renderBoundingBox (const Handle(OpenGl_Workspace)& theWor
   }
 
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
-  const Handle(OpenGl_TextureSet) aPrevTexture = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+  const Handle(OpenGl_TextureSet) aPrevTexture = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
   const Graphic3d_ZLayerSettings& aLayer = myGraphicDriver->ZLayerSettings (myZLayer);
   const Graphic3d_Vec3d aMoveVec = myTrsfPers.IsNull()
                                && !aLayer.OriginTransformation().IsNull()
@@ -95,7 +95,7 @@ void OpenGl_Structure::renderBoundingBox (const Handle(OpenGl_Workspace)& theWor
     aCtx->core11->glDisableClientState (GL_VERTEX_ARRAY);
   }
 #endif
-  aCtx->BindTextures (aPrevTexture);
+  aCtx->BindTextures (aPrevTexture, Handle(OpenGl_ShaderProgram)());
 }
 
 // =======================================================================
index 2f88a72..f04c0c0 100644 (file)
@@ -278,12 +278,12 @@ void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
 // =======================================================================
 void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
 {
-  const OpenGl_Aspects* aTextAspect = theWorkspace->ApplyAspects();
+  const OpenGl_Aspects* aTextAspect = theWorkspace->ApplyAspects (false); // do not bind textures as they will be disabled anyway
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
-  const Handle(OpenGl_TextureSet) aPrevTexture = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
 
   // Bind custom shader program or generate default version
   aCtx->ShaderManager()->BindFontProgram (aTextAspect->ShaderProgramRes (aCtx));
+  const Handle(OpenGl_TextureSet) aPrevTexture = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
 
   if (myText->HasPlane() && myText->HasOwnAnchorPoint())
   {
@@ -306,7 +306,7 @@ void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
   // restore aspects
   if (!aPrevTexture.IsNull())
   {
-    aCtx->BindTextures (aPrevTexture);
+    aCtx->BindTextures (aPrevTexture, Handle(OpenGl_ShaderProgram)());
   }
 
   // restore Z buffer settings
index 0841286..e7ffd82 100644 (file)
@@ -140,7 +140,7 @@ public:
 
   //! Initialize the texture with Graphic3d_TextureMap.
   //! It is an universal way to initialize.
-  //! Sitable initialization method will be chosen. 
+  //! Suitable initialization method will be chosen.
   Standard_EXPORT bool Init (const Handle(OpenGl_Context)&       theCtx,
                              const Handle(Graphic3d_TextureMap)& theTextureMap);
 
index bc42d12..e676cd7 100644 (file)
 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_TextureSet, Standard_Transient)
 
 // =======================================================================
+// function : OpenGl_TextureSet
+// purpose  :
+// =======================================================================
+OpenGl_TextureSet::OpenGl_TextureSet (const Handle(OpenGl_Texture)& theTexture)
+: myTextures (0, 0),
+  myTextureSetBits (Graphic3d_TextureSetBits_NONE)
+{
+  if (!theTexture.IsNull())
+  {
+    myTextures.ChangeFirst().Texture = theTexture;
+    myTextures.ChangeFirst().Unit = theTexture->Sampler()->Parameters()->TextureUnit();
+  }
+}
+
+// =======================================================================
 // function : IsModulate
 // purpose  :
 // =======================================================================
 bool OpenGl_TextureSet::IsModulate() const
 {
   return myTextures.IsEmpty()
-      || myTextures.First().IsNull()
-      || myTextures.First()->Sampler()->Parameters()->IsModulate();
+      || myTextures.First().Texture.IsNull()
+      || myTextures.First().Texture->Sampler()->Parameters()->IsModulate();
 }
 
 // =======================================================================
@@ -41,10 +56,10 @@ bool OpenGl_TextureSet::HasNonPointSprite() const
   }
   else if (myTextures.Size() == 1)
   {
-    return !myTextures.First().IsNull()
-        && !myTextures.First()->IsPointSprite();
+    return !myTextures.First().Texture.IsNull()
+        && !myTextures.First().Texture->IsPointSprite();
   }
-  return !myTextures.First().IsNull();
+  return !myTextures.First().Texture.IsNull();
 }
 
 // =======================================================================
@@ -54,6 +69,6 @@ bool OpenGl_TextureSet::HasNonPointSprite() const
 bool OpenGl_TextureSet::HasPointSprite() const
 {
   return !myTextures.IsEmpty()
-      && !myTextures.Last().IsNull()
-      &&  myTextures.Last()->IsPointSprite();
+      && !myTextures.Last().Texture.IsNull()
+      &&  myTextures.Last().Texture->IsPointSprite();
 }
index 748ba7d..e2ce50c 100644 (file)
@@ -15,6 +15,7 @@
 #define _OpenGl_TextureSet_Header
 
 #include <Graphic3d_TextureSet.hxx>
+#include <Graphic3d_TextureSetBits.hxx>
 
 class OpenGl_Texture;
 
@@ -24,8 +25,20 @@ class OpenGl_TextureSet : public Standard_Transient
   DEFINE_STANDARD_RTTIEXT(OpenGl_TextureSet, Standard_Transient)
 public:
 
+  //! Texture slot - combination of Texture and binding Unit.
+  struct TextureSlot
+  {
+    Handle(OpenGl_Texture) Texture;
+    Graphic3d_TextureUnit  Unit;
+
+    operator const Handle(OpenGl_Texture)& () const { return Texture; }
+    operator       Handle(OpenGl_Texture)& ()       { return Texture; }
+
+    TextureSlot() : Unit (Graphic3d_TextureUnit_0) {}
+  };
+
   //! Class for iterating texture set.
-  class Iterator : public NCollection_Array1<Handle(OpenGl_Texture)>::Iterator
+  class Iterator : public NCollection_Array1<TextureSlot>::Iterator
   {
   public:
     //! Empty constructor.
@@ -36,26 +49,37 @@ public:
     {
       if (!theSet.IsNull())
       {
-        NCollection_Array1<Handle(OpenGl_Texture)>::Iterator::Init (theSet->myTextures);
+        NCollection_Array1<TextureSlot>::Iterator::Init (theSet->myTextures);
       }
     }
+
+    //! Access texture.
+    const Handle(OpenGl_Texture)& Value() const { return NCollection_Array1<TextureSlot>::Iterator::Value().Texture; }
+    Handle(OpenGl_Texture)& ChangeValue()       { return NCollection_Array1<TextureSlot>::Iterator::ChangeValue().Texture; }
+
+    //! Access texture unit.
+    Graphic3d_TextureUnit  Unit() const { return NCollection_Array1<TextureSlot>::Iterator::Value().Unit; }
+    Graphic3d_TextureUnit& ChangeUnit() { return NCollection_Array1<TextureSlot>::Iterator::ChangeValue().Unit; }
   };
 
 public:
 
   //! Empty constructor.
-  OpenGl_TextureSet() {}
+  OpenGl_TextureSet() : myTextureSetBits (Graphic3d_TextureSetBits_NONE) {}
 
   //! Constructor.
   OpenGl_TextureSet (Standard_Integer theNbTextures)
-  : myTextures (0, theNbTextures - 1) {}
+  : myTextures (0, theNbTextures - 1),
+    myTextureSetBits (Graphic3d_TextureSetBits_NONE) {}
 
   //! Constructor for a single texture.
-  OpenGl_TextureSet (const Handle(OpenGl_Texture)& theTexture)
-  : myTextures (0, 0)
-  {
-    myTextures.ChangeFirst() = theTexture;
-  }
+  Standard_EXPORT OpenGl_TextureSet (const Handle(OpenGl_Texture)& theTexture);
+
+  //! Return texture units declared within the program, @sa Graphic3d_TextureSetBits.
+  Standard_Integer TextureSetBits() const { return myTextureSetBits; }
+
+  //! Return texture units declared within the program, @sa Graphic3d_TextureSetBits.
+  Standard_Integer& ChangeTextureSetBits() { return myTextureSetBits; }
 
   //! Return TRUE if texture array is empty.
   Standard_Boolean IsEmpty() const { return myTextures.IsEmpty(); }
@@ -70,22 +94,25 @@ public:
   Standard_Integer Upper() const { return myTextures.Upper(); }
 
   //! Return the first texture.
-  const Handle(OpenGl_Texture)& First() const { return myTextures.First(); }
+  const Handle(OpenGl_Texture)& First() const { return myTextures.First().Texture; }
 
   //! Return the first texture.
-  Handle(OpenGl_Texture)& ChangeFirst() { return myTextures.ChangeFirst(); }
+  Handle(OpenGl_Texture)& ChangeFirst() { return myTextures.ChangeFirst().Texture; }
 
   //! Return the last texture.
-  const Handle(OpenGl_Texture)& Last() const { return myTextures.Last(); }
+  const Handle(OpenGl_Texture)& Last() const { return myTextures.Last().Texture; }
 
   //! Return the last texture.
-  Handle(OpenGl_Texture)& ChangeLast() { return myTextures.ChangeLast(); }
+  Handle(OpenGl_Texture)& ChangeLast() { return myTextures.ChangeLast().Texture; }
+
+  //! Return the last texture unit.
+  Graphic3d_TextureUnit& ChangeLastUnit() { return myTextures.ChangeLast().Unit; }
 
   //! Return the texture at specified position within [0, Size()) range.
-  const Handle(OpenGl_Texture)& Value (Standard_Integer theIndex) const { return myTextures.Value (theIndex); }
+  const Handle(OpenGl_Texture)& Value (Standard_Integer theIndex) const { return myTextures.Value (theIndex).Texture; }
 
   //! Return the texture at specified position within [0, Size()) range.
-  Handle(OpenGl_Texture)& ChangeValue (Standard_Integer theIndex) { return myTextures.ChangeValue (theIndex); }
+  Handle(OpenGl_Texture)& ChangeValue (Standard_Integer theIndex) { return myTextures.ChangeValue (theIndex).Texture; }
 
   //! Return TRUE if texture color modulation has been enabled for the first texture
   //! or if texture is not set at all.
@@ -100,12 +127,14 @@ public:
   //! Nullify all handles.
   void InitZero()
   {
-    myTextures.Init (Handle(OpenGl_Texture)());
+    myTextures.Init (TextureSlot());
+    myTextureSetBits = Graphic3d_TextureSetBits_NONE;
   }
 
 protected:
 
-  NCollection_Array1<Handle(OpenGl_Texture)> myTextures;
+  NCollection_Array1<TextureSlot> myTextures;
+  Standard_Integer myTextureSetBits;
 
 };
 
index 2ee86d6..cd69af0 100644 (file)
@@ -277,14 +277,13 @@ void OpenGl_View::initTextureEnv (const Handle(OpenGl_Context)& theContext)
     return;
   }
 
-  myTextureEnv = new OpenGl_TextureSet (1);
-  Handle(OpenGl_Texture)& aTextureEnv = myTextureEnv->ChangeFirst();
-  aTextureEnv = new OpenGl_Texture (myTextureEnvData->GetId(), myTextureEnvData->GetParams());
-  Handle(Image_PixMap) anImage = myTextureEnvData->GetImage();
-  if (!anImage.IsNull())
+  Handle(OpenGl_Texture) aTextureEnv = new OpenGl_Texture (myTextureEnvData->GetId(), myTextureEnvData->GetParams());
+  if (Handle(Image_PixMap) anImage = myTextureEnvData->GetImage())
   {
     aTextureEnv->Init (theContext, *anImage, myTextureEnvData->Type(), true);
   }
+  myTextureEnv = new OpenGl_TextureSet (aTextureEnv);
+  myTextureEnv->ChangeTextureSetBits() = Graphic3d_TextureSetBits_BaseColor;
 }
 
 // =======================================================================
index b667440..86ba3c1 100644 (file)
@@ -403,9 +403,9 @@ OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_Aspects* theA
 
   aResMat.BSDF.Kc = aBSDF.Kc;
   aResMat.BSDF.Ks = aBSDF.Ks;
-  aResMat.BSDF.Kd = BVH_Vec4f (aBSDF.Kd, -1.f); // no texture
-  aResMat.BSDF.Kt = BVH_Vec4f (aBSDF.Kt,  0.f);
-  aResMat.BSDF.Le = BVH_Vec4f (aBSDF.Le,  0.f);
+  aResMat.BSDF.Kd = BVH_Vec4f (aBSDF.Kd, -1.0f); // no base color texture
+  aResMat.BSDF.Kt = BVH_Vec4f (aBSDF.Kt, -1.0f); // no metallic-roughness texture
+  aResMat.BSDF.Le = BVH_Vec4f (aBSDF.Le, -1.0f); // no emissive texture
 
   aResMat.BSDF.Absorption = aBSDF.Absorption;
 
@@ -428,11 +428,26 @@ OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_Aspects* theA
 
   if (theGlContext->HasRayTracingTextures())
   {
-    const Handle(OpenGl_Texture)& aTexture = aTextureSet->First();
-    buildTextureTransform (aTexture->Sampler()->Parameters(), aResMat.TextureTransform);
-
-    // write texture ID to diffuse w-component
-    aResMat.Diffuse.w() = aResMat.BSDF.Kd.w() = static_cast<Standard_ShortReal> (myRaytraceGeometry.AddTexture (aTexture));
+    // write texture ID to diffuse w-components
+    for (OpenGl_TextureSet::Iterator aTexIter (aTextureSet); aTexIter.More(); aTexIter.Next())
+    {
+      const Handle(OpenGl_Texture)& aTexture = aTexIter.Value();
+      if (aTexIter.Unit() == Graphic3d_TextureUnit_BaseColor)
+      {
+        buildTextureTransform (aTexture->Sampler()->Parameters(), aResMat.TextureTransform);
+        aResMat.Diffuse.w() = aResMat.BSDF.Kd.w() = static_cast<Standard_ShortReal> (myRaytraceGeometry.AddTexture (aTexture));
+      }
+      else if (aTexIter.Unit() == Graphic3d_TextureUnit_MetallicRoughness)
+      {
+        buildTextureTransform (aTexture->Sampler()->Parameters(), aResMat.TextureTransform);
+        aResMat.BSDF.Kt.w() = static_cast<Standard_ShortReal> (myRaytraceGeometry.AddTexture (aTexture));
+      }
+      else if (aTexIter.Unit() == Graphic3d_TextureUnit_Emissive)
+      {
+        buildTextureTransform (aTexture->Sampler()->Parameters(), aResMat.TextureTransform);
+        aResMat.BSDF.Le.w() = static_cast<Standard_ShortReal> (myRaytraceGeometry.AddTexture (aTexture));
+      }
+    }
   }
   else if (!myIsRaytraceWarnTextures)
   {
index d46bc85..18b1210 100644 (file)
@@ -1311,7 +1311,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
   }
 
   renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate);
-  aContext->BindTextures (Handle(OpenGl_TextureSet)());
+  aContext->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
 
   // Apply restored view matrix.
   aContext->ApplyWorldViewMatrix();
@@ -1530,7 +1530,7 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
     }
   #endif
 
-    aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+    aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
 
     const Graphic3d_TypeOfTextureFilter aFilter = (aDrawSizeX == aReadSizeX && aDrawSizeY == aReadSizeY) ? Graphic3d_TOTF_NEAREST : Graphic3d_TOTF_BILINEAR;
     const GLint aFilterGl = aFilter == Graphic3d_TOTF_NEAREST ? GL_NEAREST : GL_LINEAR;
@@ -1674,7 +1674,7 @@ void OpenGl_View::drawStereoPair (OpenGl_FrameBuffer* theDrawFbo)
   aCtx->core20fwd->glDepthMask (GL_TRUE);
   aCtx->core20fwd->glEnable (GL_DEPTH_TEST);
 
-  aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+  aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
   OpenGl_VertexBuffer* aVerts = initBlitQuad (myToFlipOutput);
 
   const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
index 8e6e308..476d529 100644 (file)
@@ -238,7 +238,7 @@ const OpenGl_Aspects* OpenGl_Workspace::SetAspects (const OpenGl_Aspects* theAsp
 // function : ApplyAspects
 // purpose  :
 // =======================================================================
-const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects()
+const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects (bool theToBindTextures)
 {
   if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC)
   {
@@ -305,15 +305,10 @@ const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects()
     myGlContext->SetShadingMaterial (myAspectsSet, myHighlightStyle);
   }
 
-  const Handle(OpenGl_TextureSet)& aTextureSet = myAspectsSet->TextureSet (myGlContext, ToHighlight());
-  if (!aTextureSet.IsNull()
-   || myAspectsSet->Aspect()->ToMapTexture())
+  if (theToBindTextures)
   {
-    myGlContext->BindTextures (aTextureSet);
-  }
-  else
-  {
-    myGlContext->BindTextures (myEnvironmentTexture);
+    const Handle(OpenGl_TextureSet)& aTextureSet = TextureSet();
+    myGlContext->BindTextures (aTextureSet, Handle(OpenGl_ShaderProgram)());
   }
 
   if ((myView->myShadingModel == Graphic3d_TOSM_PBR
@@ -359,7 +354,7 @@ Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer t
 
   // create the FBO
   const Handle(OpenGl_Context)& aCtx = GetGlContext();
-  aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+  aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
   Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer();
   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_SRGB8_ALPHA8, GL_DEPTH24_STENCIL8, 0))
   {
index 3a6974e..6b8b6b6 100644 (file)
@@ -148,9 +148,20 @@ public:
   //! Assign new aspects (will be applied within ApplyAspects()).
   Standard_EXPORT const OpenGl_Aspects* SetAspects (const OpenGl_Aspects* theAspect);
 
+  //! Return TextureSet from set Aspects or Environment texture.
+  const Handle(OpenGl_TextureSet)& TextureSet() const
+  {
+    const Handle(OpenGl_TextureSet)& aTextureSet = myAspectsSet->TextureSet (myGlContext, ToHighlight());
+    return !aTextureSet.IsNull()
+          || myAspectsSet->Aspect()->ToMapTexture()
+          ? aTextureSet
+          : myEnvironmentTexture;
+  }
+
   //! Apply aspects.
+  //! @param theToBindTextures flag to bind texture set defined by applied aspect
   //! @return aspect set by SetAspects()
-  Standard_EXPORT const OpenGl_Aspects* ApplyAspects();
+  Standard_EXPORT const OpenGl_Aspects* ApplyAspects (bool theToBindTextures = true);
 
   //! Clear the applied aspect state to default values.
   void ResetAppliedAspect();
index 53a45bc..0081b83 100644 (file)
@@ -175,49 +175,76 @@ uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sour
 #endif
 #endif
 
-// Converts roughness value from range [0, 1] to real value for calculations
+#if defined(THE_IS_PBR)
+//! Converts roughness value from range [0, 1] to real value for calculations
 float occRoughness (in float theNormalizedRoughness);
 
-// Front material properties accessors
-#if !defined(THE_IS_PBR)
-vec4  occFrontMaterial_Emission(void);            //!< Emission color
-vec4  occFrontMaterial_Ambient(void);             //!< Ambient  reflection
-vec4  occFrontMaterial_Diffuse(void);             //!< Diffuse  reflection
-vec4  occFrontMaterial_Specular(void);            //!< Specular reflection
-float occFrontMaterial_Shininess(void);           //!< Specular exponent
-float occFrontMaterial_Transparency(void);        //!< Transparency coefficient
+// Front/back material properties accessors
+vec4  occPBRMaterial_Color(in bool theIsFront);    //!< Base color of PBR material
+float occPBRMaterial_Metallic(in bool theIsFront); //!< Metallic coefficient
+float occPBRMaterial_NormalizedRoughness(in bool theIsFront); //!< Normalized roughness coefficient
+vec3  occPBRMaterial_Emission(in bool theIsFront); //!< Light intensity emitted by material
+float occPBRMaterial_IOR(in bool theIsFront);      //!< Index of refraction
 #else
-vec4  occPBRFrontMaterial_Color(void);               //!< Base color of PBR material
-float occPBRFrontMaterial_Metallic(void);            //!< Metallic coefficient
-float occPBRFrontMaterial_Roughness(void);           //!< Roughness coefficient
-float occPBRFrontMaterial_NormalizedRoughness(void); //!< Normalized roughness coefficient
-vec3  occPBRFrontMaterial_Emission(void);            //!< Light intensity emitted by material
-float occPBRFrontMaterial_IOR(void);                 //!< Index of refraction
-#endif
+// Front material properties accessors
+vec4  occFrontMaterial_Emission(void);           //!< Emission color
+vec4  occFrontMaterial_Ambient(void);            //!< Ambient  reflection
+vec4  occFrontMaterial_Diffuse(void);            //!< Diffuse  reflection
+vec4  occFrontMaterial_Specular(void);           //!< Specular reflection
+float occFrontMaterial_Shininess(void);          //!< Specular exponent
+float occFrontMaterial_Transparency(void);       //!< Transparency coefficient
 
 // Back material properties accessors
-#if !defined(THE_IS_PBR)
 vec4  occBackMaterial_Emission(void);            //!< Emission color
 vec4  occBackMaterial_Ambient(void);             //!< Ambient  reflection
 vec4  occBackMaterial_Diffuse(void);             //!< Diffuse  reflection
 vec4  occBackMaterial_Specular(void);            //!< Specular reflection
 float occBackMaterial_Shininess(void);           //!< Specular exponent
 float occBackMaterial_Transparency(void);        //!< Transparency coefficient
-#else
-vec4  occPBRBackMaterial_Color(void);               //!< Base color of PBR material
-float occPBRBackMaterial_Metallic(void);            //!< Metallic coefficient
-float occPBRBackMaterial_Roughness(void);           //!< Roughness coefficient
-float occPBRBackMaterial_NormalizedRoughness(void); //!< Normalized roughness coefficient
-vec3  occPBRBackMaterial_Emission(void);            //!< Light intensity emitted by material
-float occPBRBackMaterial_IOR(void);                 //!< Index of refraction
 #endif
 
 #ifdef THE_HAS_DEFAULT_SAMPLER
-#define occActiveSampler    occSampler0                //!< alias for backward compatibility
-#define occSamplerBaseColor occSampler0                //!< alias to a base color texture
-uniform               sampler2D occSampler0;           //!< current active sampler;
+#define occActiveSampler    occSampler0  //!< alias for backward compatibility
+#define occSamplerBaseColor occSampler0  //!< alias to a base color texture
+uniform sampler2D           occSampler0; //!< current active sampler;
+#endif                                   //!  occSampler1, occSampler2,... should be defined in GLSL program body for multitexturing
+
+#if defined(THE_HAS_TEXTURE_COLOR)
+#define occTextureColor(theMatColor, theTexCoord) (theMatColor * occTexture2D(occSamplerBaseColor, theTexCoord))
+#else
+#define occTextureColor(theMatColor, theTexCoord) theMatColor
+#endif
+
+#if defined(THE_HAS_TEXTURE_OCCLUSION) && defined(FRAGMENT_SHADER)
+uniform sampler2D occSamplerOcclusion;   //!< R occlusion texture sampler
+#define occTextureOcclusion(theColor, theTexCoord) theColor *= occTexture2D(occSamplerOcclusion, theTexCoord).r;
+#else
+#define occTextureOcclusion(theColor, theTexCoord)
 #endif
-                                                       //!  occSampler1, occSampler2,... should be defined in GLSL program body for multitexturing
+
+#if defined(THE_HAS_TEXTURE_EMISSIVE) && defined(FRAGMENT_SHADER)
+uniform sampler2D occSamplerEmissive;    //!< RGB emissive texture sampler
+#define occTextureEmissive(theMatEmis, theTexCoord) (theMatEmis * occTexture2D(occSamplerEmissive, theTexCoord).rgb)
+#else
+#define occTextureEmissive(theMatEmis, theTexCoord) theMatEmis
+#endif
+
+#if defined(THE_HAS_TEXTURE_NORMAL) && defined(FRAGMENT_SHADER)
+uniform sampler2D occSamplerNormal;      //!< XYZ normal texture sampler with W==0 indicating no texture
+#define occTextureNormal(theTexCoord) occTexture2D(occSamplerNormal, theTexCoord)
+#else
+#define occTextureNormal(theTexCoord) vec4(0.0) // no normal map
+#endif
+
+#if defined(THE_HAS_TEXTURE_METALROUGHNESS) && defined(FRAGMENT_SHADER)
+uniform sampler2D occSamplerMetallicRoughness; //!< BG metallic-roughness texture sampler
+#define occTextureRoughness(theRoug, theTexCoord) (theRoug * occTexture2D(occSamplerMetallicRoughness, theTexCoord).g)
+#define occTextureMetallic(theMet,   theTexCoord) (theMet  * occTexture2D(occSamplerMetallicRoughness, theTexCoord).b)
+#else
+#define occTextureRoughness(theRoug, theTexCoord) theRoug
+#define occTextureMetallic(theMet,   theTexCoord) theMet
+#endif
+
 uniform               vec4      occColor;              //!< color value (in case of disabled lighting)
 uniform THE_PREC_ENUM int       occDistinguishingMode; //!< Are front and back faces distinguished?
 uniform THE_PREC_ENUM int       occTextureEnable;      //!< Is texture enabled?
index 047c159..a2521a5 100644 (file)
@@ -52,22 +52,12 @@ uniform vec4 occPbrFrontMaterial[3];
 uniform vec4 occPbrBackMaterial[3];
 
 #define MIN_ROUGHNESS 0.01
-// Converts roughness value from range [0, 1] to real value for calculations
 float occRoughness (in float theNormalizedRoughness) { return theNormalizedRoughness * (1.0 - MIN_ROUGHNESS) + MIN_ROUGHNESS; }
-
-vec4  occPBRFrontMaterial_Color(void)     { return occPbrFrontMaterial[0]; }
-vec3  occPBRFrontMaterial_Emission(void)  { return occPbrFrontMaterial[1].rgb; }
-float occPBRFrontMaterial_IOR(void)       { return occPbrFrontMaterial[1].w; }
-float occPBRFrontMaterial_Metallic(void)  { return occPbrFrontMaterial[2].b; }
-float occPBRFrontMaterial_Roughness(void) { return occRoughness (occPbrFrontMaterial[2].g); }
-float occPBRFrontMaterial_NormalizedRoughness(void) { return occPbrFrontMaterial[2].g; }
-
-vec4  occPBRBackMaterial_Color(void)     { return occPbrBackMaterial[0]; }
-vec3  occPBRBackMaterial_Emission(void)  { return occPbrBackMaterial[1].rgb; }
-float occPBRBackMaterial_IOR(void)       { return occPbrBackMaterial[1].w; }
-float occPBRBackMaterial_Metallic(void)  { return occPbrBackMaterial[2].b; }
-float occPBRBackMaterial_Roughness(void) { return occRoughness (occPbrBackMaterial[2].g); }
-float occPBRBackMaterial_NormalizedRoughness(void) { return occPbrBackMaterial[2].g; }
+vec4  occPBRMaterial_Color(in bool theIsFront)     { return theIsFront ? occPbrFrontMaterial[0]     : occPbrBackMaterial[0]; }
+vec3  occPBRMaterial_Emission(in bool theIsFront)  { return theIsFront ? occPbrFrontMaterial[1].rgb : occPbrBackMaterial[1].rgb; }
+float occPBRMaterial_IOR(in bool theIsFront)       { return theIsFront ? occPbrFrontMaterial[1].w   : occPbrBackMaterial[1].w; }
+float occPBRMaterial_Metallic(in bool theIsFront)  { return theIsFront ? occPbrFrontMaterial[2].b   : occPbrBackMaterial[2].b; }
+float occPBRMaterial_NormalizedRoughness(in bool theIsFront) { return theIsFront ? occPbrFrontMaterial[2].g : occPbrBackMaterial[2].g; }
 #else
 uniform vec4 occFrontMaterial[5];
 uniform vec4 occBackMaterial[5];
index f70d99f..fbc1327 100644 (file)
@@ -34,14 +34,14 @@ struct SBSDF
   //! Weight of coat specular/glossy BRDF.
   vec4 Kc;
 
-  //! Weight of base diffuse BRDF.
+  //! Weight of base diffuse BRDF + base color texture index in W.
   vec4 Kd;
 
   //! Weight of base specular/glossy BRDF.
   vec4 Ks;
 
-  //! Weight of base specular/glossy BTDF.
-  vec3 Kt;
+  //! Weight of base specular/glossy BTDF + metallic-roughness texture index in W.
+  vec4 Kt;
 
   //! Fresnel coefficients of coat layer.
   vec3 FresnelCoat;
@@ -816,11 +816,16 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
     aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w));
     aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w));
     aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w));
-    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w)).rgb;
+    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w));
+
+    // fetch Fresnel reflectance for both layers
+    aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;
+    aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;
+
+    vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w));
 
     // compute smooth normal (in parallel with fetch)
     vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
-
     aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
                                dot (aInvTransf1, aNormal),
                                dot (aInvTransf2, aNormal)));
@@ -828,7 +833,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
     SLocalSpace aSpace = buildLocalSpace (aNormal);
 
 #ifdef USE_TEXTURES
-    if (aBSDF.Kd.w >= 0.f)
+    if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || anLE.w >= 0.0)
     {
       vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
       vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
@@ -836,20 +841,36 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
       aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
                            dot (aTrsfRow2, aTexCoord));
 
-      vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.f);
-      aBSDF.Kd.rgb *= aTexColor.rgb * aTexColor.w;
-      if (aTexColor.w != 1.0f)
+      if (anLE.w >= 0.0)
+      {
+        anLE.rgb *= textureLod (sampler2D (uTextureSamplers[int (anLE.w)]), aTexCoord.st, 0.0).rgb;
+      }
+      if (aBSDF.Kt.w >= 0.0)
       {
-        // mix transparency BTDF with texture alpha-channel
-        aBSDF.Kt = (UNIT - aTexColor.www) + aTexColor.w * aBSDF.Kt;
+        vec2 aTexMetRough = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kt.w)]), aTexCoord.st, 0.0).bg;
+        float aPbrMetal = aTexMetRough.x;
+        float aPbrRough2 = aTexMetRough.y * aTexMetRough.y;
+        aBSDF.Ks.a *= aPbrRough2;
+        // 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
+        aBSDF.Kd.rgb = aBSDF.FresnelBase * (1.0 - aPbrMetal);
+        aBSDF.FresnelBase *= aPbrMetal;
+      }
+      if (aBSDF.Kd.w >= 0.0)
+      {
+        vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.0);
+        vec3 aDiff = aTexColor.rgb * aTexColor.a;
+        aBSDF.Kd.rgb *= aDiff;
+        aBSDF.FresnelBase *= aDiff;
+        if (aTexColor.a != 1.0)
+        {
+          // mix transparency BTDF with texture alpha-channel
+          aBSDF.Ks.rgb *= aTexColor.a;
+          aBSDF.Kt.rgb = (UNIT - aTexColor.aaa) + aTexColor.a * aBSDF.Kt.rgb;
+        }
       }
     }
 #endif
 
-    // fetch Fresnel reflectance for both layers
-    aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;
-    aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;
-
     if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))
     {
       aExpPDF = 1.f / uLightCount;
@@ -893,7 +914,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
     }
 
     // account for self-emission
-    aRadiance += aThroughput * texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;
+    aRadiance += aThroughput * anLE.rgb;
 
     if (aInMedium) // handle attenuation
     {
index 3b31ea9..b2e47cd 100644 (file)
@@ -55,22 +55,12 @@ static const char Shaders_DeclarationsImpl_glsl[] =
   "uniform vec4 occPbrBackMaterial[3];\n"
   "\n"
   "#define MIN_ROUGHNESS 0.01\n"
-  "// Converts roughness value from range [0, 1] to real value for calculations\n"
   "float occRoughness (in float theNormalizedRoughness) { return theNormalizedRoughness * (1.0 - MIN_ROUGHNESS) + MIN_ROUGHNESS; }\n"
-  "\n"
-  "vec4  occPBRFrontMaterial_Color(void)     { return occPbrFrontMaterial[0]; }\n"
-  "vec3  occPBRFrontMaterial_Emission(void)  { return occPbrFrontMaterial[1].rgb; }\n"
-  "float occPBRFrontMaterial_IOR(void)       { return occPbrFrontMaterial[1].w; }\n"
-  "float occPBRFrontMaterial_Metallic(void)  { return occPbrFrontMaterial[2].b; }\n"
-  "float occPBRFrontMaterial_Roughness(void) { return occRoughness (occPbrFrontMaterial[2].g); }\n"
-  "float occPBRFrontMaterial_NormalizedRoughness(void) { return occPbrFrontMaterial[2].g; }\n"
-  "\n"
-  "vec4  occPBRBackMaterial_Color(void)     { return occPbrBackMaterial[0]; }\n"
-  "vec3  occPBRBackMaterial_Emission(void)  { return occPbrBackMaterial[1].rgb; }\n"
-  "float occPBRBackMaterial_IOR(void)       { return occPbrBackMaterial[1].w; }\n"
-  "float occPBRBackMaterial_Metallic(void)  { return occPbrBackMaterial[2].b; }\n"
-  "float occPBRBackMaterial_Roughness(void) { return occRoughness (occPbrBackMaterial[2].g); }\n"
-  "float occPBRBackMaterial_NormalizedRoughness(void) { return occPbrBackMaterial[2].g; }\n"
+  "vec4  occPBRMaterial_Color(in bool theIsFront)     { return theIsFront ? occPbrFrontMaterial[0]     : occPbrBackMaterial[0]; }\n"
+  "vec3  occPBRMaterial_Emission(in bool theIsFront)  { return theIsFront ? occPbrFrontMaterial[1].rgb : occPbrBackMaterial[1].rgb; }\n"
+  "float occPBRMaterial_IOR(in bool theIsFront)       { return theIsFront ? occPbrFrontMaterial[1].w   : occPbrBackMaterial[1].w; }\n"
+  "float occPBRMaterial_Metallic(in bool theIsFront)  { return theIsFront ? occPbrFrontMaterial[2].b   : occPbrBackMaterial[2].b; }\n"
+  "float occPBRMaterial_NormalizedRoughness(in bool theIsFront) { return theIsFront ? occPbrFrontMaterial[2].g : occPbrBackMaterial[2].g; }\n"
   "#else\n"
   "uniform vec4 occFrontMaterial[5];\n"
   "uniform vec4 occBackMaterial[5];\n"
index 586183a..c0e596d 100644 (file)
@@ -178,49 +178,76 @@ static const char Shaders_Declarations_glsl[] =
   "#endif\n"
   "#endif\n"
   "\n"
-  "// Converts roughness value from range [0, 1] to real value for calculations\n"
+  "#if defined(THE_IS_PBR)\n"
+  "//! Converts roughness value from range [0, 1] to real value for calculations\n"
   "float occRoughness (in float theNormalizedRoughness);\n"
   "\n"
-  "// Front material properties accessors\n"
-  "#if !defined(THE_IS_PBR)\n"
-  "vec4  occFrontMaterial_Emission(void);            //!< Emission color\n"
-  "vec4  occFrontMaterial_Ambient(void);             //!< Ambient  reflection\n"
-  "vec4  occFrontMaterial_Diffuse(void);             //!< Diffuse  reflection\n"
-  "vec4  occFrontMaterial_Specular(void);            //!< Specular reflection\n"
-  "float occFrontMaterial_Shininess(void);           //!< Specular exponent\n"
-  "float occFrontMaterial_Transparency(void);        //!< Transparency coefficient\n"
+  "// Front/back material properties accessors\n"
+  "vec4  occPBRMaterial_Color(in bool theIsFront);    //!< Base color of PBR material\n"
+  "float occPBRMaterial_Metallic(in bool theIsFront); //!< Metallic coefficient\n"
+  "float occPBRMaterial_NormalizedRoughness(in bool theIsFront); //!< Normalized roughness coefficient\n"
+  "vec3  occPBRMaterial_Emission(in bool theIsFront); //!< Light intensity emitted by material\n"
+  "float occPBRMaterial_IOR(in bool theIsFront);      //!< Index of refraction\n"
   "#else\n"
-  "vec4  occPBRFrontMaterial_Color(void);               //!< Base color of PBR material\n"
-  "float occPBRFrontMaterial_Metallic(void);            //!< Metallic coefficient\n"
-  "float occPBRFrontMaterial_Roughness(void);           //!< Roughness coefficient\n"
-  "float occPBRFrontMaterial_NormalizedRoughness(void); //!< Normalized roughness coefficient\n"
-  "vec3  occPBRFrontMaterial_Emission(void);            //!< Light intensity emitted by material\n"
-  "float occPBRFrontMaterial_IOR(void);                 //!< Index of refraction\n"
-  "#endif\n"
+  "// Front material properties accessors\n"
+  "vec4  occFrontMaterial_Emission(void);           //!< Emission color\n"
+  "vec4  occFrontMaterial_Ambient(void);            //!< Ambient  reflection\n"
+  "vec4  occFrontMaterial_Diffuse(void);            //!< Diffuse  reflection\n"
+  "vec4  occFrontMaterial_Specular(void);           //!< Specular reflection\n"
+  "float occFrontMaterial_Shininess(void);          //!< Specular exponent\n"
+  "float occFrontMaterial_Transparency(void);       //!< Transparency coefficient\n"
   "\n"
   "// Back material properties accessors\n"
-  "#if !defined(THE_IS_PBR)\n"
   "vec4  occBackMaterial_Emission(void);            //!< Emission color\n"
   "vec4  occBackMaterial_Ambient(void);             //!< Ambient  reflection\n"
   "vec4  occBackMaterial_Diffuse(void);             //!< Diffuse  reflection\n"
   "vec4  occBackMaterial_Specular(void);            //!< Specular reflection\n"
   "float occBackMaterial_Shininess(void);           //!< Specular exponent\n"
   "float occBackMaterial_Transparency(void);        //!< Transparency coefficient\n"
-  "#else\n"
-  "vec4  occPBRBackMaterial_Color(void);               //!< Base color of PBR material\n"
-  "float occPBRBackMaterial_Metallic(void);            //!< Metallic coefficient\n"
-  "float occPBRBackMaterial_Roughness(void);           //!< Roughness coefficient\n"
-  "float occPBRBackMaterial_NormalizedRoughness(void); //!< Normalized roughness coefficient\n"
-  "vec3  occPBRBackMaterial_Emission(void);            //!< Light intensity emitted by material\n"
-  "float occPBRBackMaterial_IOR(void);                 //!< Index of refraction\n"
   "#endif\n"
   "\n"
   "#ifdef THE_HAS_DEFAULT_SAMPLER\n"
-  "#define occActiveSampler    occSampler0                //!< alias for backward compatibility\n"
-  "#define occSamplerBaseColor occSampler0                //!< alias to a base color texture\n"
-  "uniform               sampler2D occSampler0;           //!< current active sampler;\n"
+  "#define occActiveSampler    occSampler0  //!< alias for backward compatibility\n"
+  "#define occSamplerBaseColor occSampler0  //!< alias to a base color texture\n"
+  "uniform sampler2D           occSampler0; //!< current active sampler;\n"
+  "#endif                                   //!  occSampler1, occSampler2,... should be defined in GLSL program body for multitexturing\n"
+  "\n"
+  "#if defined(THE_HAS_TEXTURE_COLOR)\n"
+  "#define occTextureColor(theMatColor, theTexCoord) (theMatColor * occTexture2D(occSamplerBaseColor, theTexCoord))\n"
+  "#else\n"
+  "#define occTextureColor(theMatColor, theTexCoord) theMatColor\n"
+  "#endif\n"
+  "\n"
+  "#if defined(THE_HAS_TEXTURE_OCCLUSION) && defined(FRAGMENT_SHADER)\n"
+  "uniform sampler2D occSamplerOcclusion;   //!< R occlusion texture sampler\n"
+  "#define occTextureOcclusion(theColor, theTexCoord) theColor *= occTexture2D(occSamplerOcclusion, theTexCoord).r;\n"
+  "#else\n"
+  "#define occTextureOcclusion(theColor, theTexCoord)\n"
   "#endif\n"
-  "                                                       //!  occSampler1, occSampler2,... should be defined in GLSL program body for multitexturing\n"
+  "\n"
+  "#if defined(THE_HAS_TEXTURE_EMISSIVE) && defined(FRAGMENT_SHADER)\n"
+  "uniform sampler2D occSamplerEmissive;    //!< RGB emissive texture sampler\n"
+  "#define occTextureEmissive(theMatEmis, theTexCoord) (theMatEmis * occTexture2D(occSamplerEmissive, theTexCoord).rgb)\n"
+  "#else\n"
+  "#define occTextureEmissive(theMatEmis, theTexCoord) theMatEmis\n"
+  "#endif\n"
+  "\n"
+  "#if defined(THE_HAS_TEXTURE_NORMAL) && defined(FRAGMENT_SHADER)\n"
+  "uniform sampler2D occSamplerNormal;      //!< XYZ normal texture sampler with W==0 indicating no texture\n"
+  "#define occTextureNormal(theTexCoord) occTexture2D(occSamplerNormal, theTexCoord)\n"
+  "#else\n"
+  "#define occTextureNormal(theTexCoord) vec4(0.0) // no normal map\n"
+  "#endif\n"
+  "\n"
+  "#if defined(THE_HAS_TEXTURE_METALROUGHNESS) && defined(FRAGMENT_SHADER)\n"
+  "uniform sampler2D occSamplerMetallicRoughness; //!< BG metallic-roughness texture sampler\n"
+  "#define occTextureRoughness(theRoug, theTexCoord) (theRoug * occTexture2D(occSamplerMetallicRoughness, theTexCoord).g)\n"
+  "#define occTextureMetallic(theMet,   theTexCoord) (theMet  * occTexture2D(occSamplerMetallicRoughness, theTexCoord).b)\n"
+  "#else\n"
+  "#define occTextureRoughness(theRoug, theTexCoord) theRoug\n"
+  "#define occTextureMetallic(theMet,   theTexCoord) theMet\n"
+  "#endif\n"
+  "\n"
   "uniform               vec4      occColor;              //!< color value (in case of disabled lighting)\n"
   "uniform THE_PREC_ENUM int       occDistinguishingMode; //!< Are front and back faces distinguished?\n"
   "uniform THE_PREC_ENUM int       occTextureEnable;      //!< Is texture enabled?\n"
index 138abbb..6d33da8 100644 (file)
@@ -37,14 +37,14 @@ static const char Shaders_PathtraceBase_fs[] =
   "  //! Weight of coat specular/glossy BRDF.\n"
   "  vec4 Kc;\n"
   "\n"
-  "  //! Weight of base diffuse BRDF.\n"
+  "  //! Weight of base diffuse BRDF + base color texture index in W.\n"
   "  vec4 Kd;\n"
   "\n"
   "  //! Weight of base specular/glossy BRDF.\n"
   "  vec4 Ks;\n"
   "\n"
-  "  //! Weight of base specular/glossy BTDF.\n"
-  "  vec3 Kt;\n"
+  "  //! Weight of base specular/glossy BTDF + metallic-roughness texture index in W.\n"
+  "  vec4 Kt;\n"
   "\n"
   "  //! Fresnel coefficients of coat layer.\n"
   "  vec3 FresnelCoat;\n"
@@ -819,11 +819,16 @@ static const char Shaders_PathtraceBase_fs[] =
   "    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)).rgb;\n"
+  "    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.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"
+  "\n"
+  "    vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w));\n"
   "\n"
   "    // compute smooth normal (in parallel with fetch)\n"
   "    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n"
-  "\n"
   "    aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n"
   "                               dot (aInvTransf1, aNormal),\n"
   "                               dot (aInvTransf2, aNormal)));\n"
@@ -831,7 +836,7 @@ static const char Shaders_PathtraceBase_fs[] =
   "    SLocalSpace aSpace = buildLocalSpace (aNormal);\n"
   "\n"
   "#ifdef USE_TEXTURES\n"
-  "    if (aBSDF.Kd.w >= 0.f)\n"
+  "    if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.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"
@@ -839,20 +844,36 @@ static const char Shaders_PathtraceBase_fs[] =
   "      aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n"
   "                           dot (aTrsfRow2, aTexCoord));\n"
   "\n"
-  "      vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.f);\n"
-  "      aBSDF.Kd.rgb *= aTexColor.rgb * aTexColor.w;\n"
-  "      if (aTexColor.w != 1.0f)\n"
+  "      if (anLE.w >= 0.0)\n"
+  "      {\n"
+  "        anLE.rgb *= textureLod (sampler2D (uTextureSamplers[int (anLE.w)]), aTexCoord.st, 0.0).rgb;\n"
+  "      }\n"
+  "      if (aBSDF.Kt.w >= 0.0)\n"
   "      {\n"
-  "        // mix transparency BTDF with texture alpha-channel\n"
-  "        aBSDF.Kt = (UNIT - aTexColor.www) + aTexColor.w * aBSDF.Kt;\n"
+  "        vec2 aTexMetRough = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kt.w)]), aTexCoord.st, 0.0).bg;\n"
+  "        float aPbrMetal = aTexMetRough.x;\n"
+  "        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"
+  "      }\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"
+  "        if (aTexColor.a != 1.0)\n"
+  "        {\n"
+  "          // mix transparency BTDF with texture alpha-channel\n"
+  "          aBSDF.Ks.rgb *= aTexColor.a;\n"
+  "          aBSDF.Kt.rgb = (UNIT - aTexColor.aaa) + aTexColor.a * aBSDF.Kt.rgb;\n"
+  "        }\n"
   "      }\n"
   "    }\n"
   "#endif\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"
-  "\n"
   "    if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))\n"
   "    {\n"
   "      aExpPDF = 1.f / uLightCount;\n"
@@ -896,7 +917,7 @@ static const char Shaders_PathtraceBase_fs[] =
   "    }\n"
   "\n"
   "    // account for self-emission\n"
-  "    aRadiance += aThroughput * texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;\n"
+  "    aRadiance += aThroughput * anLE.rgb;\n"
   "\n"
   "    if (aInMedium) // handle attenuation\n"
   "    {\n"
index 3fba8d7..c865308 100644 (file)
@@ -236,10 +236,7 @@ void XCAFDoc_VisMaterial::FillMaterialAspect (Graphic3d_MaterialAspect& theAspec
     aPbr.SetColor    (myPbrMat.BaseColor);
     aPbr.SetMetallic (myPbrMat.Metallic);
     aPbr.SetRoughness(myPbrMat.Roughness);
-    if (myPbrMat.EmissiveTexture.IsNull()) // TODO Temporal measure until emissive map will be implemented
-    {
-      aPbr.SetEmission(myPbrMat.EmissiveFactor);
-    }
+    aPbr.SetEmission (myPbrMat.EmissiveFactor);
     theAspect.SetPBRMaterial (aPbr);
     theAspect.SetBSDF (Graphic3d_BSDF::CreateMetallicRoughness (aPbr));
   }
@@ -262,43 +259,41 @@ void XCAFDoc_VisMaterial::FillAspect (const Handle(Graphic3d_Aspects)& theAspect
   theAspect->SetAlphaMode (myAlphaMode , myAlphaCutOff);
   theAspect->SetSuppressBackFaces (!myIsDoubleSided);
 
-  Handle(Image_Texture) aColorTexture, aNormTexture;
-  if (!myCommonMat.DiffuseTexture.IsNull())
+  const Handle(Image_Texture)& aColorTexture = !myPbrMat.BaseColorTexture.IsNull() ? myPbrMat.BaseColorTexture : myCommonMat.DiffuseTexture;
+  Standard_Integer aNbTexUnits = 0;
+  if (!aColorTexture.IsNull())             { ++aNbTexUnits; }
+  if (!myPbrMat.EmissiveTexture.IsNull())  { ++aNbTexUnits; }
+  if (!myPbrMat.NormalTexture.IsNull())    { ++aNbTexUnits; }
+  if (!myPbrMat.OcclusionTexture.IsNull()) { ++aNbTexUnits; }
+  if (!myPbrMat.MetallicRoughnessTexture.IsNull()) { ++aNbTexUnits; }
+  if (aNbTexUnits == 0)
   {
-    aColorTexture = myCommonMat.DiffuseTexture;
+    return;
   }
-  else if (!myPbrMat.BaseColorTexture.IsNull())
+
+  Standard_Integer aTexIter = 0;
+  Handle(Graphic3d_TextureSet) aTextureSet = new Graphic3d_TextureSet (aNbTexUnits);
+  if (!aColorTexture.IsNull())
   {
-    aColorTexture = myPbrMat.BaseColorTexture;
+    aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_BaseColor));
   }
-
-  if (!myPbrMat.NormalTexture.IsNull())
+  if (!myPbrMat.EmissiveTexture.IsNull())
   {
-    aNormTexture = myPbrMat.NormalTexture;
+    aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.EmissiveTexture, Graphic3d_TextureUnit_Emissive));
   }
-
-  Standard_Integer aNbTextures = 0;
-  if (!aColorTexture.IsNull())
+  if (!myPbrMat.OcclusionTexture.IsNull())
   {
-    ++aNbTextures;
+    aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.OcclusionTexture, Graphic3d_TextureUnit_Occlusion));
   }
-  if (!aNormTexture.IsNull())
+  if (!myPbrMat.NormalTexture.IsNull())
   {
-    //++aNbTextures;
+    aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.NormalTexture, Graphic3d_TextureUnit_Normal));
   }
-  if (aNbTextures != 0)
+  if (!myPbrMat.MetallicRoughnessTexture.IsNull())
   {
-    Handle(Graphic3d_TextureSet) aTextureSet = new Graphic3d_TextureSet (aNbTextures);
-    Standard_Integer aTextureIndex = 0;
-    if (!aColorTexture.IsNull())
-    {
-      aTextureSet->SetValue (aTextureIndex++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_BaseColor));
-    }
-    if (!aNormTexture.IsNull())
-    {
-      //aTextureSet->SetValue (aTextureIndex++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_Normal));
-    }
-    theAspect->SetTextureSet (aTextureSet);
-    theAspect->SetTextureMapOn (true);
+    aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.MetallicRoughnessTexture, Graphic3d_TextureUnit_MetallicRoughness));
   }
+
+  theAspect->SetTextureSet (aTextureSet);
+  theAspect->SetTextureMapOn (true);
 }
index 1c8b3a0..798cbab 100644 (file)
@@ -31,6 +31,8 @@ XCAFPrs_Texture::XCAFPrs_Texture (const Image_Texture& theImageSource,
     myTexId = myImageSource.TextureId();
   }
   myParams->SetTextureUnit (theUnit);
+  myIsColorMap = theUnit == Graphic3d_TextureUnit_BaseColor
+              || theUnit == Graphic3d_TextureUnit_Emissive;
 }
 
 //=======================================================================
diff --git a/tests/v3d/raytrace/helmet b/tests/v3d/raytrace/helmet
new file mode 100644 (file)
index 0000000..d547ae2
--- /dev/null
@@ -0,0 +1,25 @@
+puts "========"
+puts "0031096: Visualization, TKOpenGl - support metallic-roughness texture mapping"
+puts "========"
+
+pload XDE OCAF MODELING VISUALIZATION
+catch { Close D }
+ReadGltf D [locate_data_file bug30691_DamagedHelmet.gltf]
+
+vclear
+vinit View1
+XDisplay -dispMode 1 D
+vaxo
+vcamera -persp
+vviewparams -scale 0.412548 -proj 0.54479 -0.790649 0.279424 -up -0.248339 0.166151 0.954317 -at -27.3419 382.603 -233.934
+
+vtextureenv on 2
+vlight -change 0 -intensity 2.5
+vlight -change 1 -intensity 0.3
+
+vrenderparams -shadingModel PBR
+vdump ${imagedir}/${casename}_pbr.png
+
+vrenderparams -ray -gi -rayDepth 10
+vfps 200
+vdump ${imagedir}/${casename}_pt.png