0030700: Visualization, TKOpenGl - support PBR Metallic-Roughness shading model
[occt.git] / src / OpenGl / OpenGl_View_Redraw.cxx
index 98354d4..d46bc85 100644 (file)
@@ -39,6 +39,8 @@
 #include <OpenGl_Structure.hxx>
 #include <OpenGl_ArbFBO.hxx>
 
+#include "../Textures/Textures_EnvLUT.pxx"
+
 namespace
 {
   //! Format Frame Buffer format for logging messages.
@@ -344,6 +346,65 @@ void OpenGl_View::Redraw()
     }
   }
 
+  // process PBR environment
+  if (myShadingModel == Graphic3d_TOSM_PBR
+   || myShadingModel == Graphic3d_TOSM_PBR_FACET)
+  {
+    if (!myPBREnvironment.IsNull()
+      && myPBREnvironment->SizesAreDifferent (myRenderParams.PbrEnvPow2Size,
+                                              myRenderParams.PbrEnvSpecMapNbLevels))
+    {
+      myPBREnvironment->Release (aCtx.get());
+      myPBREnvironment.Nullify();
+      myPBREnvState = OpenGl_PBREnvState_NONEXISTENT;
+      myPBREnvRequest = OpenGl_PBREnvRequest_BAKE;
+      ++myLightsRevision;
+    }
+
+    if (myPBREnvState == OpenGl_PBREnvState_NONEXISTENT
+     && aCtx->HasPBR())
+    {
+      myPBREnvironment = OpenGl_PBREnvironment::Create (aCtx, myRenderParams.PbrEnvPow2Size, myRenderParams.PbrEnvSpecMapNbLevels);
+      myPBREnvState = myPBREnvironment.IsNull() ? OpenGl_PBREnvState_UNAVAILABLE : OpenGl_PBREnvState_CREATED;
+      if (myPBREnvState == OpenGl_PBREnvState_CREATED)
+      {
+        Handle(OpenGl_Texture) anEnvLUT;
+        static const TCollection_AsciiString THE_SHARED_ENV_LUT_KEY("EnvLUT");
+        if (!aCtx->GetResource (THE_SHARED_ENV_LUT_KEY, anEnvLUT))
+        {
+          Handle(Graphic3d_TextureParams) aParams = new Graphic3d_TextureParams();
+          aParams->SetFilter (Graphic3d_TOTF_BILINEAR);
+          aParams->SetRepeat (Standard_False);
+          aParams->SetTextureUnit (aCtx->PBREnvLUTTexUnit());
+          anEnvLUT = new OpenGl_Texture(THE_SHARED_ENV_LUT_KEY, aParams);
+          Handle(Image_PixMap) aPixMap = new Image_PixMap();
+          aPixMap->InitWrapper (Image_Format_RGF, (Standard_Byte*)Textures_EnvLUT, Textures_EnvLUTSize, Textures_EnvLUTSize);
+          OpenGl_TextureFormat aTexFormat = OpenGl_TextureFormat::FindFormat (aCtx, aPixMap->Format(), false);
+        #if defined(GL_ES_VERSION_2_0)
+          // GL_RG32F is not texture-filterable format on OpenGL ES without OES_texture_float_linear extension.
+          // GL_RG16F is texture-filterable since OpenGL ES 3.0 and can be initialized from 32-bit floats.
+          // Note that it is expected that GL_RG16F has enough precision for this table, so that it can be used also on desktop OpenGL.
+          //if (!aCtx->hasTexFloatLinear)
+          aTexFormat.SetInternalFormat (GL_RG16F);
+        #endif
+          if (!aTexFormat.IsValid()
+           || !anEnvLUT->Init (aCtx, aTexFormat, Graphic3d_Vec2i((Standard_Integer)Textures_EnvLUTSize), Graphic3d_TOT_2D, aPixMap.get()))
+          {
+            aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Failed allocation of LUT for PBR");
+            anEnvLUT.Nullify();
+          }
+          aCtx->ShareResource (THE_SHARED_ENV_LUT_KEY, anEnvLUT);
+        }
+        if (!anEnvLUT.IsNull())
+        {
+          anEnvLUT->Bind (aCtx);
+        }
+        myWorkspace->ApplyAspects();
+      }
+    }
+    processPBREnvRequest (aCtx);
+  }
+
   // create color and coverage accumulation buffers required for OIT algorithm
   if (toUseOit)
   {
@@ -938,7 +999,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
    || aLightsRevision != myLightsRevision)
   {
     myLightsRevision = aLightsRevision;
-    aManager->UpdateLightSourceStateTo (aLights);
+    aManager->UpdateLightSourceStateTo (aLights, SpecIBLMapLevels());
     myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index());
   }
 
@@ -1020,7 +1081,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
   }
 #endif
 
-  aManager->SetShadingModel (myShadingModel);
+  aManager->SetShadingModel (OpenGl_ShaderManager::PBRShadingModelFallback (myShadingModel, checkPBRAvailability()));
 
   // Redraw 3d scene
   if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye)
@@ -1848,3 +1909,64 @@ bool OpenGl_View::chooseOitColorConfiguration (const Handle(OpenGl_Context)& the
   }
   return false; // color combination does not exist
 }
+
+// =======================================================================
+// function : checkPBRAvailability
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_View::checkPBRAvailability() const
+{
+  return myWorkspace->GetGlContext()->HasPBR()
+      && !myPBREnvironment.IsNull();
+}
+
+// =======================================================================
+// function : bakePBREnvironment
+// purpose  :
+// =======================================================================
+void OpenGl_View::bakePBREnvironment (const Handle(OpenGl_Context)& theCtx)
+{
+  const Handle(OpenGl_TextureSet)& aTextureSet = myCubeMapParams->TextureSet (theCtx);
+  if (!aTextureSet.IsNull()
+   && !aTextureSet->IsEmpty())
+  {
+    myPBREnvironment->Bake (theCtx,
+                            aTextureSet->First(),
+                            myBackgroundCubeMap->ZIsInverted(),
+                            myBackgroundCubeMap->IsTopDown(),
+                            myRenderParams.PbrEnvBakingDiffNbSamples,
+                            myRenderParams.PbrEnvBakingSpecNbSamples,
+                            myRenderParams.PbrEnvBakingProbability);
+  }
+  else
+  {
+    myPBREnvironment->Clear (theCtx);
+  }
+}
+
+// =======================================================================
+// function : clearPBREnvironment
+// purpose  :
+// =======================================================================
+void OpenGl_View::clearPBREnvironment (const Handle(OpenGl_Context)& theCtx)
+{
+  myPBREnvironment->Clear (theCtx);
+}
+
+// =======================================================================
+// function : clearPBREnvironment
+// purpose  :
+// =======================================================================
+void OpenGl_View::processPBREnvRequest (const Handle(OpenGl_Context)& theCtx)
+{
+  if (myPBREnvState == OpenGl_PBREnvState_CREATED)
+  {
+    switch (myPBREnvRequest)
+    {
+      case OpenGl_PBREnvRequest_NONE:  return;
+      case OpenGl_PBREnvRequest_BAKE:  bakePBREnvironment  (theCtx); break;
+      case OpenGl_PBREnvRequest_CLEAR: clearPBREnvironment (theCtx); break;
+    }
+  }
+  myPBREnvRequest = OpenGl_PBREnvRequest_NONE;
+}