]> OCCT Git - occt.git/commitdiff
0032083: Visualization, TKOpenGl - PBR rendering is unavailable on Apple A12 Bionic...
authorkgv <kgv@opencascade.com>
Sun, 24 Jan 2021 15:31:54 +0000 (18:31 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 29 Jan 2021 16:51:18 +0000 (19:51 +0300)
Added "#define occLight_Index(theId) 0" workaround allowing to compile
a single light source PBR shading program on OpenGL ES 2.0,
as it disallows non-constant index expressions (even trivially deducable at compile-time).

PBR lookup table is now automatically resized to RGBA format
when RG texture format is unsupported (OpenGL ES 2.0).

OpenGl_ShaderManager now allows compiling PBR shaders
using WebGL 1.0 + GL_EXT_shader_texture_lod extension.

PBR IBL baking GLSL program has been redisigned to use
if/else to avoid non-constant index expressions.
Diffuse baking implements packing float values into a temporary RGBA8 texture
as a fallback solution on WebGL 1.0 implementations supporting float textures
but not as FBO render targets.

OpenGl_PBREnvironment now uses GL_FRAMEBUFFER instead of GL_DRAW_FRAMEBUFFER
for compatibility with OpenGL ES 2.0.

19 files changed:
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_PBREnvironment.cxx
src/OpenGl/OpenGl_PBREnvironment.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_Texture.cxx
src/OpenGl/OpenGl_Texture.hxx
src/OpenGl/OpenGl_TextureFormat.cxx
src/OpenGl/OpenGl_TextureFormat.hxx
src/OpenGl/OpenGl_View.cxx
src/Shaders/Declarations.glsl
src/Shaders/DirectionalLightShadow.glsl
src/Shaders/PBREnvBaking.fs
src/Shaders/PBREnvBaking.vs
src/Shaders/Shaders_Declarations_glsl.pxx
src/Shaders/Shaders_DirectionalLightShadow_glsl.pxx
src/Shaders/Shaders_PBREnvBaking_fs.pxx
src/Shaders/Shaders_PBREnvBaking_vs.pxx

index 16c68647c4bfd7b2afed8e83e71efb1d8f602df2..9147d26bcf62c18d8d20cc661d17c9489e3fdd6e 100644 (file)
@@ -158,6 +158,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   hasTexSRGB (Standard_False),
   hasFboSRGB (Standard_False),
   hasSRGBControl (Standard_False),
+  hasFboRenderMipmap (Standard_False),
 #if defined(GL_ES_VERSION_2_0)
   hasFlatShading (OpenGl_FeatureNotAvailable),
 #else
@@ -1228,6 +1229,20 @@ void OpenGl_Context::ReadGlVersion (Standard_Integer& theGlVerMajor,
   // read numbers
   theGlVerMajor = atoi (aMajorStr);
   theGlVerMinor = atoi (aMinorStr);
+#if defined(__EMSCRIPTEN__)
+  if (theGlVerMajor >= 3)
+  {
+    if (!toCheckVer3
+     || ::strstr (aVerStr, "WebGL 1.0") != NULL)
+    {
+      Message::SendWarning() << "Warning! OpenGL context reports version " << theGlVerMajor << "." << theGlVerMinor
+                             << " but WebGL 2.0 was unavailable\n"
+                             << "Fallback to OpenGL ES 2.0 will be used instead of reported version";
+      theGlVerMajor = 2;
+      theGlVerMinor = 0;
+    }
+  }
+#endif
 
   if (theGlVerMajor <= 0)
   {
@@ -1540,6 +1555,8 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
              || CheckExtension ("GL_OES_rgb8_rgba8");
   hasTexSRGB  = IsGlGreaterEqual (3, 0);
   hasFboSRGB  = IsGlGreaterEqual (3, 0);
+  hasFboRenderMipmap = IsGlGreaterEqual (3, 0)
+                    || CheckExtension ("GL_OES_fbo_render_mipmap");
   hasSRGBControl = CheckExtension ("GL_EXT_sRGB_write_control");
   // NPOT textures has limited support within OpenGL ES 2.0
   // which are relaxed by OpenGL ES 3.0 or some extensions
@@ -1983,6 +2000,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   hasTexSRGB       = IsGlGreaterEqual (2, 1);
   hasFboSRGB       = IsGlGreaterEqual (2, 1);
   hasSRGBControl   = hasFboSRGB;
+  hasFboRenderMipmap = Standard_True;
   arbDrawBuffers   = CheckExtension ("GL_ARB_draw_buffers");
   arbNPTW          = CheckExtension ("GL_ARB_texture_non_power_of_two");
   arbTexFloat      = IsGlGreaterEqual (3, 0)
@@ -3415,10 +3433,11 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   // check whether PBR shading model is supported
   myHasPBR = arbFBO != NULL
           && myMaxTexCombined >= 4
-          && arbTexRG
           && arbTexFloat
           && (IsGlGreaterEqual (3, 0)
-        #if !defined(GL_ES_VERSION_2_0)
+        #if defined(GL_ES_VERSION_2_0)
+          || CheckExtension ("GL_EXT_shader_texture_lod")
+        #else
           || (IsGlGreaterEqual (2, 1) && CheckExtension ("GL_EXT_gpu_shader4"))
         #endif
              );
index 3c25ca97d4520a9b22ada17f4c47a4b244d48747..8bde7aaea4f9e13749e3fc939165be344e3251d8 100644 (file)
@@ -1085,6 +1085,7 @@ public: //! @name extensions
   Standard_Boolean       hasTexSRGB;         //!< sRGB texture    formats (desktop OpenGL 2.1, OpenGL ES 3.0 or GL_EXT_texture_sRGB)
   Standard_Boolean       hasFboSRGB;         //!< sRGB FBO render targets (desktop OpenGL 2.1, OpenGL ES 3.0)
   Standard_Boolean       hasSRGBControl;     //!< sRGB write control (any desktop OpenGL, OpenGL ES + GL_EXT_sRGB_write_control extension)
+  Standard_Boolean       hasFboRenderMipmap; //!< FBO render target could be non-zero mimap level of texture
   OpenGl_FeatureFlag     hasFlatShading;     //!< Complex flag indicating support of Flat shading (Graphic3d_TOSM_FACET) (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_standard_derivatives)
   OpenGl_FeatureFlag     hasGlslBitwiseOps;  //!< GLSL supports bitwise operations; OpenGL 3.0 / OpenGL ES 3.0 (GLSL 130 / GLSL ES 300) or OpenGL 2.1 + GL_EXT_gpu_shader4
   OpenGl_FeatureFlag     hasDrawBuffers;     //!< Complex flag indicating support of multiple draw buffers (desktop OpenGL 2.0, OpenGL ES 3.0, GL_ARB_draw_buffers, GL_EXT_draw_buffers)
index e68f7c714debaa6d7a2dcdbb9e15c8003ac4d70e..14188a7e4233a46058d36c18c9a89a87ae4e5f73 100644 (file)
@@ -77,7 +77,7 @@ private:
 
   void restore()
   {
-    myContext->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myFBO);
+    myContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myFBO);
     myContext->BindProgram (myShaderProgram);
     myContext->ResizeViewport (myViewport);
     myContext->core11fwd->glClearColor (myClearColor.r(), myClearColor.g(), myClearColor.b(), myClearColor.a());
@@ -159,7 +159,8 @@ OpenGl_PBREnvironment::OpenGl_PBREnvironment (const Handle(OpenGl_Context)&  the
   mySpecMapLevelsNumber (std::max (2u, std::min (theSpecMapLevelsNumber, std::max (1u, thePowOf2Size) + 1))),
   myFBO (OpenGl_FrameBuffer::NO_FRAMEBUFFER),
   myIsComplete (Standard_False),
-  myIsNeededToBeBound (Standard_True)
+  myIsNeededToBeBound (Standard_True),
+  myCanRenderFloat (Standard_True)
 {
   OpenGl_PBREnvironmentSentry aSentry (theCtx);
 
@@ -253,8 +254,9 @@ void OpenGl_PBREnvironment::Release (OpenGl_Context* theCtx)
     }
     myFBO = OpenGl_FrameBuffer::NO_FRAMEBUFFER;
   }
-  myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Release(theCtx);
+  myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Release (theCtx);
   myIBLMaps[OpenGl_TypeOfIBLMap_Specular] .Release (theCtx);
+  myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseFallback].Release (theCtx);
   myVBO.Release (theCtx);
 }
 
@@ -276,16 +278,35 @@ bool OpenGl_PBREnvironment::initTextures (const Handle(OpenGl_Context)& theCtx)
   myIBLMaps[OpenGl_TypeOfIBLMap_Specular] .Sampler()->Parameters()->SetTextureUnit (theCtx->PBRSpecIBLMapTexUnit());
   myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Sampler()->Parameters()->SetTextureUnit (theCtx->PBRDiffIBLMapSHTexUnit());
   myIBLMaps[OpenGl_TypeOfIBLMap_Specular] .Sampler()->Parameters()->SetFilter (Graphic3d_TOTF_TRILINEAR);
-  myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Sampler()->Parameters()->SetFilter(Graphic3d_TOTF_NEAREST);
+  myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Sampler()->Parameters()->SetFilter (Graphic3d_TOTF_NEAREST);
   myIBLMaps[OpenGl_TypeOfIBLMap_Specular] .Sampler()->Parameters()->SetLevelsRange (mySpecMapLevelsNumber - 1);
+  myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseFallback].Sampler()->Parameters()->SetFilter (Graphic3d_TOTF_NEAREST);
 
   // NVIDIA's driver didn't work properly with 3 channel texture for diffuse SH coefficients so that alpha channel has been added
-  return myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Init (theCtx,
-                                                        OpenGl_TextureFormat::FindFormat (theCtx, Image_Format_RGBAF, false),
-                                                        Graphic3d_Vec2i (9, 1),
-                                                        Graphic3d_TOT_2D)
-      && myIBLMaps[OpenGl_TypeOfIBLMap_Specular].InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)(),
-                                                              Standard_Size(1) << myPow2Size, Image_Format_RGB, true, false);
+  if (!myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Init (theCtx,
+                                                      OpenGl_TextureFormat::FindFormat (theCtx, Image_Format_RGBAF, false),
+                                                      Graphic3d_Vec2i (9, 1), Graphic3d_TOT_2D))
+  {
+    Message::SendFail() << "OpenGl_PBREnvironment, DiffuseSH texture creation failed";
+    return false;
+  }
+
+  if (!myIBLMaps[OpenGl_TypeOfIBLMap_Specular].InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)(),
+                                                            Standard_Size(1) << myPow2Size, Image_Format_RGB, true, false))
+  {
+    Message::SendFail() << "OpenGl_PBREnvironment, Specular texture creation failed";
+    return false;
+  }
+
+  if (!myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseFallback].Init (theCtx,
+                                                            OpenGl_TextureFormat::FindFormat (theCtx, Image_Format_RGBA, false),
+                                                            Graphic3d_Vec2i (10, 4), Graphic3d_TOT_2D))
+  {
+    Message::SendFail() << "OpenGl_PBREnvironment, DiffuseFallback texture creation failed";
+    return false;
+  }
+
+  return true;
 }
 
 // =======================================================================
@@ -319,28 +340,98 @@ bool OpenGl_PBREnvironment::initFBO (const Handle(OpenGl_Context)& theCtx)
 // purpose  :
 // =======================================================================
 bool OpenGl_PBREnvironment::processDiffIBLMap (const Handle(OpenGl_Context)& theCtx,
-                                               Standard_Boolean              theIsDrawAction,
-                                               Standard_Size                 theNbSamples)
+                                               const BakingParams* theDrawParams)
 {
-  theCtx->arbFBO->glFramebufferTexture2D (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-                                          myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].TextureId(), 0);
-  const Standard_Integer aViewport[4] = { 0, 0, 9, 1 };
+  const OpenGl_TypeOfIBLMap aRendMapId = myCanRenderFloat ? OpenGl_TypeOfIBLMap_DiffuseSH : OpenGl_TypeOfIBLMap_DiffuseFallback;
+  Image_PixMap anImageF;
+  if (!myCanRenderFloat)
+  {
+    anImageF.InitZero (Image_Format_RGBAF, myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].SizeX(), myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].SizeY());
+  }
+
+  theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                                          myIBLMaps[aRendMapId].TextureId(), 0);
+  const Standard_Integer aViewport[4] = { 0, 0, 9, myCanRenderFloat ? 1 : 3 };
   theCtx->ResizeViewport(aViewport);
-  if (theIsDrawAction)
+  if (theDrawParams != NULL)
   {
-    theCtx->ActiveProgram()->SetUniform(theCtx, "occNbSpecIBLLevels", 0);
-    theCtx->ActiveProgram()->SetUniform(theCtx, "uSamplesNum", static_cast<Standard_Integer>(theNbSamples));
+    if (!theCtx->ShaderManager()->BindPBREnvBakingProgram (aRendMapId))
+    {
+      return false;
+    }
 
+    const Handle(OpenGl_ShaderProgram)& aProg = theCtx->ActiveProgram();
+    aProg->SetSampler (theCtx, "uEnvMap", theCtx->PBRSpecIBLMapTexUnit());
+    aProg->SetUniform (theCtx, "uZCoeff", theDrawParams->IsZInverted ? -1 :  1);
+    aProg->SetUniform (theCtx, "uYCoeff", theDrawParams->IsTopDown   ?  1 : -1);
+    aProg->SetUniform (theCtx, "uSamplesNum", Standard_Integer(theDrawParams->NbDiffSamples));
+
+    myVBO.BindAttribute (theCtx, Graphic3d_TOA_POS);
     theCtx->core11fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+    myVBO.UnbindAttribute (theCtx, Graphic3d_TOA_POS);
+
+    if (!myCanRenderFloat)
+    {
+      // unpack RGBA8 values to floats
+      Image_PixMap anImageIn;
+      anImageIn.InitZero (myCanRenderFloat ? Image_Format_RGBAF : Image_Format_RGBA, aViewport[2], aViewport[3]);
+      theCtx->core11fwd->glReadPixels (0, 0, aViewport[2], aViewport[3],
+                                       GL_RGBA, myCanRenderFloat ? GL_FLOAT : GL_UNSIGNED_BYTE, anImageIn.ChangeData());
+      const GLenum anErr = theCtx->core11fwd->glGetError();
+      if (anErr != GL_NO_ERROR)
+      {
+        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                             TCollection_AsciiString ("Unable to read PBR baking diffuse texture. Error ") + OpenGl_Context::FormatGlError (anErr));
+      }
+      for (Standard_Size aValIter = 0; aValIter < anImageIn.SizeX(); ++aValIter)
+      {
+        Graphic3d_Vec4 aVal;
+        if (myCanRenderFloat)
+        {
+          aVal = anImageIn.Value<Graphic3d_Vec4> (0, aValIter);
+        }
+        else
+        {
+          const int32_t aPacked[3] = { anImageIn.Value<int32_t> (2, aValIter), anImageIn.Value<int32_t> (1, aValIter), anImageIn.Value<int32_t> (0, aValIter) };
+          aVal[0] = aPacked[0] / 2147483647.0f;
+          aVal[1] = aPacked[1] / 2147483647.0f;
+          aVal[2] = aPacked[2] / 2147483647.0f;
+        }
+        anImageF.ChangeValue<Graphic3d_Vec4> (0, aValIter) = aVal;
+      }
+    }
   }
   else
   {
-    theCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
+    if (myCanRenderFloat)
+    {
+      theCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
 
-    theCtx->core11fwd->glEnable (GL_SCISSOR_TEST);
-    theCtx->core11fwd->glClearColor (0.f, 0.f, 0.f, 1.f);
-    theCtx->core11fwd->glScissor (1, 0, 8, 1);
-    theCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
+      theCtx->core11fwd->glEnable (GL_SCISSOR_TEST);
+      theCtx->core11fwd->glClearColor (0.f, 0.f, 0.f, 1.f);
+      theCtx->core11fwd->glScissor (1, 0, 8, 1);
+      theCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
+      theCtx->core11fwd->glDisable (GL_SCISSOR_TEST);
+    }
+    else
+    {
+      anImageF.ChangeValue<Graphic3d_Vec4> (0, 0) = Graphic3d_Vec4 (1.0f);
+      for (Standard_Size aValIter = 1; aValIter < anImageF.SizeX(); ++aValIter)
+      {
+        anImageF.ChangeValue<Graphic3d_Vec4> (0, aValIter) = Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
+      }
+    }
+  }
+
+  if (!myCanRenderFloat)
+  {
+    if (!myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].Init (theCtx,
+                                                        OpenGl_TextureFormat::FindFormat (theCtx, Image_Format_RGBAF, false),
+                                                        Graphic3d_Vec2i (9, 1), Graphic3d_TOT_2D, &anImageF))
+    {
+      Message::SendFail() << "OpenGl_PBREnvironment, DiffuseSH texture update failed";
+      return false;
+    }
   }
 
   return true;
@@ -351,34 +442,52 @@ bool OpenGl_PBREnvironment::processDiffIBLMap (const Handle(OpenGl_Context)& the
 // purpose  :
 // =======================================================================
 bool OpenGl_PBREnvironment::processSpecIBLMap (const Handle(OpenGl_Context)& theCtx,
-                                               Standard_Boolean              theIsDrawAction,
-                                               Standard_Integer              theEnvMapSize,
-                                               Standard_Size                 theNbSamples,
-                                               Standard_ShortReal            theProbability)
+                                               const BakingParams* theDrawParams)
 {
-  if (theIsDrawAction)
+  if (theDrawParams != NULL)
   {
-    theCtx->ActiveProgram()->SetUniform (theCtx, "occNbSpecIBLLevels", Standard_Integer(mySpecMapLevelsNumber));
-    theCtx->ActiveProgram()->SetUniform (theCtx, "uEnvMapSize", theEnvMapSize);
+    if (!theCtx->ShaderManager()->BindPBREnvBakingProgram (OpenGl_TypeOfIBLMap_Specular))
+    {
+      return false;
+    }
+
+    const Handle(OpenGl_ShaderProgram)& aProg = theCtx->ActiveProgram();
+    const float aSolidAngleSource = float(4.0 * M_PI / (6.0 * float(theDrawParams->EnvMapSize * theDrawParams->EnvMapSize)));
+    aProg->SetSampler (theCtx, "uEnvMap", theCtx->PBRSpecIBLMapTexUnit());
+    aProg->SetUniform (theCtx, "uZCoeff", theDrawParams->IsZInverted ? -1 :  1);
+    aProg->SetUniform (theCtx, "uYCoeff", theDrawParams->IsTopDown   ?  1 : -1);
+    aProg->SetUniform (theCtx, "occNbSpecIBLLevels",   Standard_Integer(mySpecMapLevelsNumber));
+    aProg->SetUniform (theCtx, "uEnvSolidAngleSource", aSolidAngleSource);
+    myVBO.BindAttribute (theCtx, Graphic3d_TOA_POS);
   }
 
+  const bool canRenderMipmaps = theCtx->hasFboRenderMipmap;
+  const OpenGl_TextureFormat aTexFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, myIBLMaps[OpenGl_TypeOfIBLMap_Specular].SizedFormat());
+#if !defined(GL_ES_VERSION_2_0)
+  const GLint anIntFormat = aTexFormat.InternalFormat();
+#else
+  // ES 2.0 does not support sized formats and format conversions - them detected from data type
+  const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? aTexFormat.InternalFormat() : aTexFormat.PixelFormat();
+#endif
+
   for (int aLevelIter = mySpecMapLevelsNumber - 1;; --aLevelIter)
   {
     const Standard_Integer aSize = 1 << (myPow2Size - aLevelIter);
     const Standard_Integer aViewport[4] = { 0, 0, aSize, aSize };
     theCtx->ResizeViewport (aViewport);
-    if (theIsDrawAction)
+    if (theDrawParams != NULL)
     {
-      Standard_Integer aNbSamples = static_cast<Standard_Integer>(Graphic3d_PBRMaterial::SpecIBLMapSamplesFactor (theProbability, aLevelIter / float (mySpecMapLevelsNumber - 1)) * theNbSamples);
-      theCtx->ActiveProgram()->SetUniform (theCtx, "uSamplesNum", static_cast<Standard_Integer>(aNbSamples));
+      const Standard_Integer aNbSamples = Standard_Integer(Graphic3d_PBRMaterial::SpecIBLMapSamplesFactor (theDrawParams->Probability,
+                                                                                                           aLevelIter / float (mySpecMapLevelsNumber - 1)) * theDrawParams->NbSpecSamples);
+      theCtx->ActiveProgram()->SetUniform (theCtx, "uSamplesNum",   aNbSamples);
       theCtx->ActiveProgram()->SetUniform (theCtx, "uCurrentLevel", aLevelIter);
     }
 
     for (Standard_Integer aSideIter = 0; aSideIter < 6; ++aSideIter)
     {
-      theCtx->arbFBO->glFramebufferTexture2D (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + aSideIter,
-                                              myIBLMaps[OpenGl_TypeOfIBLMap_Specular].TextureId(), aLevelIter);
-      if (theIsDrawAction)
+      theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + aSideIter,
+                                              myIBLMaps[OpenGl_TypeOfIBLMap_Specular].TextureId(), canRenderMipmaps ? aLevelIter : 0);
+      if (theDrawParams != NULL)
       {
         theCtx->ActiveProgram()->SetUniform(theCtx, "uCurrentSide", aSideIter);
         theCtx->core11fwd->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -387,6 +496,20 @@ bool OpenGl_PBREnvironment::processSpecIBLMap (const Handle(OpenGl_Context)& the
       {
         theCtx->core11fwd->glClear(GL_COLOR_BUFFER_BIT);
       }
+
+      if (!canRenderMipmaps
+        && aLevelIter != 0)
+      {
+        myIBLMaps[OpenGl_TypeOfIBLMap_Specular].Bind (theCtx, Graphic3d_TextureUnit_1);
+        theCtx->core20fwd->glCopyTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + aSideIter, aLevelIter, anIntFormat, 0, 0, (GLsizei )aSize, (GLsizei )aSize, 0);
+        myIBLMaps[OpenGl_TypeOfIBLMap_Specular].Unbind (theCtx, Graphic3d_TextureUnit_1);
+        const GLenum anErr = theCtx->core11fwd->glGetError();
+        if (anErr != GL_NO_ERROR)
+        {
+          theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                               TCollection_AsciiString ("Unable to copy cubemap mipmap level. Error ") + OpenGl_Context::FormatGlError (anErr));
+        }
+      }
     }
 
     if (aLevelIter == 0)
@@ -395,6 +518,11 @@ bool OpenGl_PBREnvironment::processSpecIBLMap (const Handle(OpenGl_Context)& the
     }
   }
 
+  if (theDrawParams != NULL)
+  {
+    myVBO.UnbindAttribute (theCtx, Graphic3d_TOA_POS);
+  }
+
   return true;
 }
 
@@ -402,23 +530,44 @@ bool OpenGl_PBREnvironment::processSpecIBLMap (const Handle(OpenGl_Context)& the
 // function : checkFBOCompletness
 // purpose  :
 // =======================================================================
-bool OpenGl_PBREnvironment::checkFBOComplentess (const Handle(OpenGl_Context)& theCtx) const
+bool OpenGl_PBREnvironment::checkFBOComplentess (const Handle(OpenGl_Context)& theCtx)
 {
-  theCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myFBO);
-  theCtx->arbFBO->glFramebufferTexture2D (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+  myCanRenderFloat = true;
+  theCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myFBO);
+  theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                                           myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseSH].TextureId(), 0);
-  if (theCtx->arbFBO->glCheckFramebufferStatus (GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+  if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
-    return false;
+    // Some WebGL 1.0 and OpenGL ES 2.0 implementations support float textures which cannot be used as render targets.
+    // This capability could be exposed by WEBGL_color_buffer_float/EXT_color_buffer_float extensions,
+    // but the simplest way is just to check FBO status.
+    // The fallback solution involves rendering into RGBA8 texture with floating values packed,
+    // and using glReadPixels() + conversion + texture upload of computed values.
+    myCanRenderFloat = false;
+    theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                                            myIBLMaps[OpenGl_TypeOfIBLMap_DiffuseFallback].TextureId(), 0);
+    if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+    {
+      Message::SendTrace() << "OpenGl_PBREnvironment, incomplete FBO for diffuse map";
+      return false;
+    }
   }
+
   for (Standard_Integer aSideIter = 0; aSideIter < 6; ++aSideIter)
   {
     for (unsigned int aLevel = 0; aLevel < mySpecMapLevelsNumber; ++aLevel)
     {
-      theCtx->arbFBO->glFramebufferTexture2D (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + aSideIter,
+      if (!theCtx->hasFboRenderMipmap
+        && aLevel != 0)
+      {
+        continue;
+      }
+
+      theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + aSideIter,
                                               myIBLMaps[OpenGl_TypeOfIBLMap_Specular].TextureId(), aLevel);
-      if (theCtx->arbFBO->glCheckFramebufferStatus (GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+      if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
       {
+        Message::SendTrace() << "OpenGl_PBREnvironment, incomplete FBO for specular map " << aSideIter << " "<< aLevel;
         return false;
       }
     }
@@ -439,21 +588,21 @@ void OpenGl_PBREnvironment::bake (const Handle(OpenGl_Context)& theCtx,
                                   Standard_ShortReal            theProbability)
 {
   myIsNeededToBeBound = Standard_True;
-  if (!theCtx->ShaderManager()->BindPBREnvBakingProgram())
-  {
-    return;
-  }
+
   theEnvMap->Bind (theCtx, theCtx->PBRSpecIBLMapTexUnit());
-  theCtx->ActiveProgram()->SetSampler (theCtx, "uEnvMap", theCtx->PBRSpecIBLMapTexUnit());
-  theCtx->ActiveProgram()->SetUniform (theCtx, "uZCoeff", theZIsInverted ? -1 : 1);
-  theCtx->ActiveProgram()->SetUniform (theCtx, "uYCoeff", theIsTopDown ? 1 : -1);
-  theCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myFBO);
-  myVBO.BindAttribute (theCtx, Graphic3d_TOA_POS);
+  theCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myFBO);
 
   OSD_Timer aTimer;
   aTimer.Start();
-  if (processSpecIBLMap (theCtx, true, theEnvMap->SizeX(), theSpecNbSamples, theProbability)
-   && processDiffIBLMap (theCtx, true, theDiffNbSamples))
+  BakingParams aDrawParams;
+  aDrawParams.NbSpecSamples = theSpecNbSamples;
+  aDrawParams.NbDiffSamples = theDiffNbSamples;
+  aDrawParams.EnvMapSize    = theEnvMap->SizeX();
+  aDrawParams.Probability   = theProbability;
+  aDrawParams.IsZInverted   = theZIsInverted;
+  aDrawParams.IsTopDown     = theIsTopDown;
+  if (processSpecIBLMap (theCtx, &aDrawParams)
+   && processDiffIBLMap (theCtx, &aDrawParams))
   {
     Message::SendTrace(TCollection_AsciiString()
       + "IBL " + myIBLMaps[OpenGl_TypeOfIBLMap_Specular].SizeX() + "x" + myIBLMaps[OpenGl_TypeOfIBLMap_Specular].SizeY()
@@ -467,7 +616,6 @@ void OpenGl_PBREnvironment::bake (const Handle(OpenGl_Context)& theCtx,
     clear (theCtx, Graphic3d_Vec3(1.0f));
   }
 
-  myVBO.UnbindAttribute (theCtx, Graphic3d_TOA_POS);
   theEnvMap->Unbind (theCtx, theCtx->PBREnvLUTTexUnit());
 }
 
@@ -479,9 +627,9 @@ void OpenGl_PBREnvironment::clear (const Handle(OpenGl_Context)& theCtx,
                                    const Graphic3d_Vec3&         theColor)
 {
   myIsNeededToBeBound = Standard_True;
-  theCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myFBO);
+  theCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myFBO);
   theCtx->core11fwd->glClearColor (theColor.r(), theColor.g(), theColor.b(), 1.f);
 
-  processSpecIBLMap (theCtx, false);
-  processDiffIBLMap (theCtx, false);
+  processSpecIBLMap (theCtx, NULL);
+  processDiffIBLMap (theCtx, NULL);
 }
index 986883ba894238e2925550c71fca1ed298fcce22..11607d86bf7f8beaeff285eda4b84012cc907af0 100644 (file)
@@ -134,7 +134,22 @@ private:
   enum OpenGl_TypeOfIBLMap
   {
     OpenGl_TypeOfIBLMap_DiffuseSH,
-    OpenGl_TypeOfIBLMap_Specular
+    OpenGl_TypeOfIBLMap_Specular,
+    OpenGl_TypeOfIBLMap_DiffuseFallback,
+  };
+
+  //! Parameters for baking IBL.
+  struct BakingParams
+  {
+    Standard_Size      NbSpecSamples;
+    Standard_Size      NbDiffSamples;
+    Standard_Integer   EnvMapSize;
+    Standard_ShortReal Probability;
+    Standard_Boolean   IsZInverted;
+    Standard_Boolean   IsTopDown;
+
+    BakingParams()
+    : NbSpecSamples (0), NbDiffSamples (0), EnvMapSize (1024), Probability (1.0f), IsZInverted (false), IsTopDown (false) {}
   };
 
   //! Initializes all textures.
@@ -156,23 +171,19 @@ private:
   //! @return false in case of failed baking or clearing
   //! Warning! Requires using of OpenGl_PBREnvironmentSentry.
   bool processDiffIBLMap (const Handle(OpenGl_Context)& theCtx,
-                          Standard_Boolean      theIsDrawAction,
-                          Standard_Size         theNbSamples = 0);
+                          const BakingParams* theDrawParams);
 
   //! Responses for specular IBL map processing.
   //! @return false in case of failed baking or clearing
   //! Warning! Requires using of OpenGl_PBREnvironmentSentry.
   bool processSpecIBLMap (const Handle(OpenGl_Context)& theCtx,
-                          Standard_Boolean   theIsDrawAction,
-                          Standard_Integer   theEnvMapSize = 1024,
-                          Standard_Size      theNbSamples = 0,
-                          Standard_ShortReal theProbability = 1.f);
+                          const BakingParams* theDrawParams);
 
   //! Checks completeness of frame buffer object for all targets
   //! (all cube map sides and levels of IBL maps).
   //! @return false in case of uncompleted frame buffer object.
   //! Warning! Requires using of OpenGl_PBREnvironmentSentry.
-  bool checkFBOComplentess (const Handle(OpenGl_Context)& theCtx) const;
+  bool checkFBOComplentess (const Handle(OpenGl_Context)& theCtx);
 
   //! Version of 'Bake' without OpenGl_PBREnvironmentSetnry.
   //! Warning! Requires using of OpenGl_PBREnvironmentSentry.
@@ -194,12 +205,13 @@ private:
   unsigned int        myPow2Size;            //!< size of IBL maps sides (real size can be calculated as 2^myPow2Size)
   unsigned int        mySpecMapLevelsNumber; //!< number of mipmap levels used in specular IBL map
 
-  OpenGl_Texture      myIBLMaps[2];          //!< IBL maps
+  OpenGl_Texture      myIBLMaps[3];          //!< IBL maps
   OpenGl_VertexBuffer myVBO;                 //!< vertex buffer object of screen rectangular
   GLuint              myFBO;                 //!< frame buffer object to generate or clear IBL maps
 
   Standard_Boolean    myIsComplete;          //!< completeness of PBR environment
   Standard_Boolean    myIsNeededToBeBound;   //!< indicates whether IBL map's textures have to be bound or it is not obligate
+  Standard_Boolean    myCanRenderFloat;      //!< indicates whether driver supports rendering into floating point texture or not
 
 };
 
index ae07acb0464f358fecb2a1dbb5ec1ec7c10db5af..a3e6f271a2a239331d095a849ddbfffbc1b58fab 100644 (file)
@@ -1764,10 +1764,17 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr
   }
   else
   {
-    if (theProgram->IsPBR()
-     && myContext->IsGlGreaterEqual (3, 0))
+    if (theProgram->IsPBR())
     {
-      theProgram->SetHeader ("#version 300 es");
+      if (myContext->IsGlGreaterEqual (3, 0))
+      {
+        theProgram->SetHeader ("#version 300 es");
+      }
+      else if (myContext->CheckExtension ("GL_EXT_shader_texture_lod"))
+      {
+        theProgram->SetHeader ("#extension GL_EXT_shader_texture_lod : enable\n"
+                               "#define textureCubeLod textureCubeLodEXT");
+      }
     }
     if ((theBits & OpenGl_PO_WriteOit) != 0
      || (theBits & OpenGl_PO_OitDepthPeeling) != 0
@@ -3165,8 +3172,9 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramBoundBox()
 // function : preparePBREnvBakingProgram
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_ShaderManager::preparePBREnvBakingProgram()
+Standard_Boolean OpenGl_ShaderManager::preparePBREnvBakingProgram (Standard_Integer theIndex)
 {
+  Standard_ASSERT_RAISE (theIndex >= 0 && theIndex <= 2,"");
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
 
@@ -3177,16 +3185,27 @@ Standard_Boolean OpenGl_ShaderManager::preparePBREnvBakingProgram()
   TCollection_AsciiString aSrcFrag = TCollection_AsciiString()
   + THE_FUNC_cubemap_vector_transform
   + Shaders_PBRDistribution_glsl
+  + ((theIndex == 0 || theIndex == 2) ? "\n#define THE_TO_BAKE_DIFFUSE\n" : "\n#define THE_TO_BAKE_SPECULAR\n")
+  + (theIndex == 2 ? "\n#define THE_TO_PACK_FLOAT\n" : "")
   + Shaders_PBREnvBaking_fs;
 
   // constant array definition requires OpenGL 2.1+ or OpenGL ES 3.0+
 #if defined(GL_ES_VERSION_2_0)
-  aProgramSrc->SetHeader ("#version 300 es");
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    aProgramSrc->SetHeader ("#version 300 es");
+  }
+  else if (myContext->CheckExtension ("GL_EXT_shader_texture_lod"))
+  {
+    aProgramSrc->SetHeader ("#extension GL_EXT_shader_texture_lod : enable\n"
+                            "#define textureCubeLod textureCubeLodEXT");
+  }
 #else
   aProgramSrc->SetHeader ("#version 120");
 #endif
 
-  defaultGlslVersion (aProgramSrc, "pbr_env_baking", 0);
+  static const char* THE_BAKE_NAMES[3] = { "pbr_env_baking_diffuse", "pbr_env_baking_specular", "pbr_env_baking_difffallback" };
+  defaultGlslVersion (aProgramSrc, THE_BAKE_NAMES[theIndex], 0);
   aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbShadowMaps (0);
@@ -3195,12 +3214,28 @@ Standard_Boolean OpenGl_ShaderManager::preparePBREnvBakingProgram()
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
   TCollection_AsciiString aKey;
-  if (!Create (aProgramSrc, aKey, myPBREnvBakingProgram))
+  if (!Create (aProgramSrc, aKey, myPBREnvBakingProgram[theIndex]))
   {
-    myPBREnvBakingProgram = new OpenGl_ShaderProgram(); // just mark as invalid
+    myPBREnvBakingProgram[theIndex] = new OpenGl_ShaderProgram(); // just mark as invalid
     return Standard_False;
   }
 
+  if (theIndex == 0
+   || theIndex == 2)
+  {
+    // workaround for old GLSL - load constants as uniform
+    myContext->BindProgram (myPBREnvBakingProgram[theIndex]);
+    const float aSHBasisFuncCoeffs[9] =
+    {
+      0.282095f * 0.282095f, 0.488603f * 0.488603f, 0.488603f * 0.488603f, 0.488603f * 0.488603f,
+      1.092548f * 1.092548f, 1.092548f * 1.092548f, 1.092548f * 1.092548f, 0.315392f * 0.315392f, 0.546274f * 0.546274f
+    };
+    const float aSHCosCoeffs[9] = { 3.141593f, 2.094395f, 2.094395f, 2.094395f, 0.785398f, 0.785398f, 0.785398f, 0.785398f, 0.785398f };
+    myPBREnvBakingProgram[theIndex]->SetUniform (myContext, myPBREnvBakingProgram[theIndex]->GetUniformLocation (myContext, "aSHBasisFuncCoeffs"), 9, aSHBasisFuncCoeffs);
+    myPBREnvBakingProgram[theIndex]->SetUniform (myContext, myPBREnvBakingProgram[theIndex]->GetUniformLocation (myContext, "aSHCosCoeffs"), 9, aSHCosCoeffs);
+    myContext->BindProgram (NULL);
+  }
+
   return Standard_True;
 }
 
index 7635518ff0ccbc6a369f72f9829edf162355c082..44f2c2d3ac8d883084e8df2c89c8c2a581898415 100644 (file)
@@ -277,13 +277,13 @@ public:
   const Handle(OpenGl_VertexBuffer)& BoundBoxVertBuffer() const { return myBoundBoxVertBuffer; }
 
   //! Bind program for IBL maps generation in PBR pipeline.
-  Standard_Boolean BindPBREnvBakingProgram()
+  Standard_Boolean BindPBREnvBakingProgram (Standard_Integer theIndex)
   {
-    if (myPBREnvBakingProgram.IsNull())
+    if (myPBREnvBakingProgram[theIndex].IsNull())
     {
-      preparePBREnvBakingProgram();
+      preparePBREnvBakingProgram (theIndex);
     }
-    return myContext->BindProgram (myPBREnvBakingProgram);
+    return myContext->BindProgram (myPBREnvBakingProgram[theIndex]);
   }
 
   //! Generates shader program to render environment cubemap as background.
@@ -814,7 +814,7 @@ protected:
                                                               Standard_Integer theBits);
 
   //! Prepare GLSL source for IBL generation used in PBR pipeline.
-  Standard_EXPORT Standard_Boolean preparePBREnvBakingProgram();
+  Standard_EXPORT Standard_Boolean preparePBREnvBakingProgram (Standard_Integer theIndex);
 
   //! Checks whether one of PBR shading models is set as default model.
   Standard_Boolean IsPbrAllowed() const { return myShadingModel == Graphic3d_TOSM_PBR
@@ -883,7 +883,7 @@ protected:
   Handle(OpenGl_ShaderProgram)       myOitDepthPeelingFlushProgram[2]; //!< standard program for OIT Depth Peeling flush (default and MSAA)
   OpenGl_MapOfShaderPrograms         myMapOfLightPrograms; //!< map of lighting programs depending on lights configuration
 
-  Handle(OpenGl_ShaderProgram)       myPBREnvBakingProgram;//!< program for IBL maps generation used in PBR pipeline
+  Handle(OpenGl_ShaderProgram)       myPBREnvBakingProgram[3]; //!< programs for IBL maps generation used in PBR pipeline (0 for Diffuse; 1 for Specular; 2 for fallback)
   Handle(Graphic3d_ShaderProgram)    myBgCubeMapProgram;   //!< program for background cubemap rendering
 
   Handle(OpenGl_ShaderProgram)       myStereoPrograms[Graphic3d_StereoMode_NB]; //!< standard stereo programs
index 2bf73d553f5398d61dc14f76f10de80848a644b9..939e5bc99125673981c767340e0d0a7065bdcffe 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <OpenGl_ArbFBO.hxx>
 #include <OpenGl_Context.hxx>
-#include <OpenGl_GlCore32.hxx>
+#include <OpenGl_GlCore45.hxx>
 #include <OpenGl_Sampler.hxx>
 #include <Graphic3d_TextureParams.hxx>
 #include <TCollection_ExtendedString.hxx>
@@ -1235,3 +1235,72 @@ Standard_Size OpenGl_Texture::EstimatedDataSize() const
   }
   return aSize;
 }
+
+// =======================================================================
+// function : ImageDump
+// purpose  :
+// =======================================================================
+bool OpenGl_Texture::ImageDump (Image_PixMap& theImage,
+                                const Handle(OpenGl_Context)& theCtx,
+                                Graphic3d_TextureUnit theTexUnit,
+                                Standard_Integer theLevel,
+                                Standard_Integer theCubeSide) const
+{
+#if !defined(GL_ES_VERSION_2_0)
+  const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, mySizedFormat);
+  if (theCtx.IsNull()
+  || !IsValid()
+  ||  theLevel < 0
+  || !aFormat.IsValid()
+  ||  aFormat.ImageFormat() == Image_Format_UNKNOWN
+  || (myTarget == GL_TEXTURE_CUBE_MAP
+   && (theCubeSide < 0 || theCubeSide > 5)))
+  {
+    return false;
+  }
+
+  GLenum aTarget = myTarget;
+  Graphic3d_Vec2i aSize (mySizeX, mySizeY);
+  if (myTarget == GL_TEXTURE_CUBE_MAP)
+  {
+    aTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + theCubeSide;
+  }
+  for (Standard_Integer aMipIter = 0; aMipIter < theLevel; ++aMipIter)
+  {
+    aSize /= 2;
+    if (aSize.x() == 0) { aSize.x() = 1; }
+    if (aSize.y() == 0) { aSize.y() = 1; }
+  }
+  if (!theImage.InitTrash (aFormat.ImageFormat(), aSize.x(), aSize.y()))
+  {
+    return false;
+  }
+
+  const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
+  theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
+  theCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+  // glGetTextureImage() allows avoiding to binding texture id, but apparently requires clean FBO binding state...
+  //if (theCtx->core45 != NULL) { theCtx->core45->glGetTextureImage (myTextureId, theLevel, aFormat.PixelFormat(), aFormat.DataType(), (GLsizei )theImage.SizeBytes(), theImage.ChangeData()); } else
+  {
+    Bind (theCtx, theTexUnit);
+    theCtx->core11fwd->glGetTexImage (aTarget, theLevel, aFormat.PixelFormat(), aFormat.DataType(), theImage.ChangeData());
+    Unbind (theCtx, theTexUnit);
+  }
+  if (theImage.Format() != aFormat.ImageFormat())
+  {
+    Image_PixMap::SwapRgbaBgra (theImage);
+  }
+
+  const bool hasErrors = theCtx->ResetErrors (true);
+  theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
+  return !hasErrors;
+#else
+  // glGetTexImage() is unavailable in OpenGL ES
+  (void )theImage;
+  (void )theCtx;
+  (void )theTexUnit;
+  (void )theLevel;
+  (void )theCubeSide;
+  return false;
+#endif
+}
index a4b2ca42e2c204af5e639f97fb413d332efedb62..03f57d959ec14cfd1c58f317b179d0227f012e73 100644 (file)
@@ -191,6 +191,19 @@ public:
   //! Returns TRUE for point sprite texture.
   virtual bool IsPointSprite() const { return false; }
 
+  //! Auxiliary method for making an image dump from texture data.
+  //! @param theImage   [out] result image data (will be overridden)
+  //! @param theCtx      [in] active GL context
+  //! @param theTexUnit  [in] texture slot to use
+  //! @param theLevel    [in] mipmap level to dump
+  //! @param theCubeSide [in] cubemap side to dump within [0, 5] range
+  //! @return FALSE on error
+  Standard_EXPORT bool ImageDump (Image_PixMap& theImage,
+                                  const Handle(OpenGl_Context)& theCtx,
+                                  Graphic3d_TextureUnit theTexUnit,
+                                  Standard_Integer theLevel = 0,
+                                  Standard_Integer theCubeSide = 0) const;
+
 public:
 
   Standard_DEPRECATED("Deprecated method, OpenGl_TextureFormat::FindFormat() should be used instead")
index b655d41add75d8816a344ef78d3320915babe2ef..ec07a2c2d2b7ad7b5da3a481e81384e81f0f27e4 100644 (file)
@@ -122,6 +122,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindFormat (const Handle(OpenGl_Conte
                                                        bool theIsColorMap)
 {
   OpenGl_TextureFormat aFormat;
+  aFormat.SetImageFormat (theFormat);
   switch (theFormat)
   {
     case Image_Format_GrayF:
@@ -414,6 +415,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RGBA);
       aFormat.SetDataType (GL_FLOAT);
+      aFormat.SetImageFormat (Image_Format_RGBAF);
       return aFormat;
     }
     case GL_R32F:
@@ -422,6 +424,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RED);
       aFormat.SetDataType (GL_FLOAT);
+      aFormat.SetImageFormat (Image_Format_GrayF);
       return aFormat;
     }
     case GL_RG32F:
@@ -430,6 +433,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RG);
       aFormat.SetDataType (GL_FLOAT);
+      aFormat.SetImageFormat (Image_Format_RGF);
       return aFormat;
     }
     case GL_RGBA16F:
@@ -438,6 +442,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RGBA);
       aFormat.SetDataType (GL_HALF_FLOAT);
+      aFormat.SetImageFormat (Image_Format_RGBAF);
       if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
       {
       #if defined(GL_ES_VERSION_2_0)
@@ -454,6 +459,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RED);
       aFormat.SetDataType (GL_HALF_FLOAT);
+      aFormat.SetImageFormat (Image_Format_GrayF);
       if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
       {
       #if defined(GL_ES_VERSION_2_0)
@@ -472,6 +478,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RGBA);
       aFormat.SetDataType (GL_UNSIGNED_BYTE);
+      aFormat.SetImageFormat (Image_Format_RGBA);
       if (theSizedFormat == GL_SRGB8_ALPHA8
       && !theCtx->ToRenderSRGB())
       {
@@ -487,6 +494,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
       aFormat.SetInternalFormat (theSizedFormat);
       aFormat.SetPixelFormat (GL_RGB);
       aFormat.SetDataType (GL_UNSIGNED_BYTE);
+      aFormat.SetImageFormat (Image_Format_RGB);
       if (theSizedFormat == GL_SRGB8
       && !theCtx->ToRenderSRGB())
       {
index d8bc04c65895b55577295997ff2eeaae0fca5269..592fc6128ccf8399ad7b16e2b15da8982acc9846 100644 (file)
@@ -66,7 +66,7 @@ public:
 public:
 
   //! Empty constructor (invalid texture format).
-  OpenGl_TextureFormat() : myInternalFormat (0), myPixelFormat (0), myDataType (0), myNbComponents (0) {}
+  OpenGl_TextureFormat() : myImageFormat (Image_Format_UNKNOWN), myInternalFormat (0), myPixelFormat (0), myDataType (0), myNbComponents (0) {}
 
   //! Return TRUE if format is defined.
   bool IsValid() const
@@ -107,6 +107,12 @@ public:
         || myInternalFormat == GL_SRGB8_ALPHA8;
   }
 
+  //! Returns image format (best match or Image_Format_UNKNOWN if no suitable fit).
+  Image_Format ImageFormat() const { return myImageFormat; }
+
+  //! Sets image format.
+  void SetImageFormat (Image_Format theFormat) { myImageFormat = theFormat; }
+
 public:
 
   //! Returns OpenGL internal format of the pixel data (example: GL_R32F).
@@ -117,6 +123,7 @@ public:
 
 private:
 
+  Image_Format myImageFormat; //!< image format
   GLint  myInternalFormat; //!< OpenGL internal format of the pixel data
   GLenum myPixelFormat;    //!< OpenGL pixel format
   GLint  myDataType;       //!< OpenGL data type of input pixel data
index cf258d9fefaabc7783f83009b173cf8a3be2f451..4d58b9eb7bc458c9f102943e90d0a10794b5c78d 100644 (file)
@@ -1194,14 +1194,34 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj)
           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);
+          if (aCtx->arbTexRG)
+          {
+            aPixMap->InitWrapper (Image_Format_RGF, (Standard_Byte*)Textures_EnvLUT, Textures_EnvLUTSize, Textures_EnvLUTSize);
+          }
+          else
+          {
+            Image_PixMap aPixMapRG;
+            aPixMapRG.InitWrapper (Image_Format_RGF, (Standard_Byte*)Textures_EnvLUT, Textures_EnvLUTSize, Textures_EnvLUTSize);
+            aPixMap->InitZero (Image_Format_RGBAF, Textures_EnvLUTSize, Textures_EnvLUTSize);
+            for (Standard_Size aRowIter = 0; aRowIter < aPixMapRG.SizeY(); ++aRowIter)
+            {
+              for (Standard_Size aColIter = 0; aColIter < aPixMapRG.SizeX(); ++aColIter)
+              {
+                const Image_ColorRGF& aPixelRG = aPixMapRG.Value<Image_ColorRGF> (aRowIter, aColIter);
+                Image_ColorRGBAF& aPixelRGBA = aPixMap->ChangeValue<Image_ColorRGBAF> (aRowIter, aColIter);
+                aPixelRGBA.r() = aPixelRG.r();
+                aPixelRGBA.g() = aPixelRG.g();
+              }
+            }
+          }
+
           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);
+          aTexFormat.SetInternalFormat (aCtx->arbTexRG ? GL_RG16F : GL_RGBA16F);
         #endif
           if (!aTexFormat.IsValid()
            || !anEnvLUT->Init (aCtx, aTexFormat, Graphic3d_Vec2i((Standard_Integer)Textures_EnvLUTSize), Graphic3d_TOT_2D, aPixMap.get()))
index 27418912ca8a0a3694b659e78dabf7c551d3707a..8b7fe60f4936552e987124018786e79ed94af9e2 100644 (file)
@@ -143,44 +143,49 @@ const int OccLightType_Spot   = 3; //!< spot            light source
 // Light sources
 uniform               vec4 occLightAmbient;      //!< Cumulative ambient color
 #if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)
+#if (THE_MAX_LIGHTS > 1)
+  #define occLight_Index(theId) theId
+#else
+  #define occLight_Index(theId) 0
+#endif
 uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sources
 
 //! Type of light source, int (see OccLightType enum).
-#define occLight_Type(theId)              occLightSourcesTypes[theId]
+#define occLight_Type(theId)              occLightSourcesTypes[occLight_Index(theId)]
 
 //! Specular intensity (equals to diffuse), vec3.
-#define occLight_Specular(theId)          occLightSources[theId * 4 + 0].rgb
+#define occLight_Specular(theId)          occLightSources[occLight_Index(theId) * 4 + 0].rgb
 
 //! Intensity of light source (>= 0), float.
-#define occLight_Intensity(theId)         occLightSources[theId * 4 + 0].a
+#define occLight_Intensity(theId)         occLightSources[occLight_Index(theId) * 4 + 0].a
 
 //! Is light a headlight, bool? DEPRECATED method.
 #define occLight_IsHeadlight(theId) false
 
 //! Position of specified light source or direction of directional light source, vec3.
-#define occLight_Position(theId)          occLightSources[theId * 4 + 1].xyz
+#define occLight_Position(theId)          occLightSources[occLight_Index(theId) * 4 + 1].xyz
 
 //! Direction of specified spot light source, vec3.
-#define occLight_SpotDirection(theId)     occLightSources[theId * 4 + 2].xyz
+#define occLight_SpotDirection(theId)     occLightSources[occLight_Index(theId) * 4 + 2].xyz
 
 //! Range on which point light source (positional or spot) can affect (>= 0), float.
-#define occLight_Range(theId)             occLightSources[theId * 4 + 2].w
+#define occLight_Range(theId)             occLightSources[occLight_Index(theId) * 4 + 2].w
 
 //! Maximum spread angle of the spot light (in radians), float.
-#define occLight_SpotCutOff(theId)        occLightSources[theId * 4 + 3].z
+#define occLight_SpotCutOff(theId)        occLightSources[occLight_Index(theId) * 4 + 3].z
 
 //! Attenuation of the spot light intensity (from 0 to 1), float.
-#define occLight_SpotExponent(theId)      occLightSources[theId * 4 + 3].w
+#define occLight_SpotExponent(theId)      occLightSources[occLight_Index(theId) * 4 + 3].w
 
 #if !defined(THE_IS_PBR)
 //! Diffuse intensity (equals to Specular), vec3.
-#define occLight_Diffuse(theId)           occLightSources[theId * 4 + 0].rgb
+#define occLight_Diffuse(theId)           occLightSources[occLight_Index(theId) * 4 + 0].rgb
 
 //! Const attenuation factor of positional light source, float.
-#define occLight_ConstAttenuation(theId)  occLightSources[theId * 4 + 3].x
+#define occLight_ConstAttenuation(theId)  occLightSources[occLight_Index(theId) * 4 + 3].x
 
 //! Linear attenuation factor of positional light source, float.
-#define occLight_LinearAttenuation(theId) occLightSources[theId * 4 + 3].y
+#define occLight_LinearAttenuation(theId) occLightSources[occLight_Index(theId) * 4 + 3].y
 #endif
 #endif
 
index 80c9a1e27f1e99b763df6718f361c23d4a31bbb6..25a90a0c26f4393df42eea3b3592352152614854 100644 (file)
@@ -14,7 +14,7 @@ float occDirectionalLightShadow (in sampler2D theShadow,
                                  in int  theId,
                                  in vec3 theNormal)
 {
-  vec4 aPosLightSpace = PosLightSpace[theId];
+  vec4 aPosLightSpace = PosLightSpace[occLight_Index(theId)];
   vec3 aLightDir = vec3 (occWorldViewMatrix * vec4 (occLight_Position (theId), 0.0));
   vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w) * 0.5 + vec3 (0.5);
   float aCurrentDepth = aProjCoords.z;
index e795c4607adea28a4e70609bcca60fc8e9e412f1..6ce89bcde57ebc11de34965ac914f8b81c55fe27 100644 (file)
@@ -1,12 +1,22 @@
 THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap
 
+#if (__VERSION__ >= 120)
 uniform int uSamplesNum;     //!< number of samples in Monte-Carlo integration
-uniform int uCurrentLevel;   //!< current level of specular IBL map (ignored in case of diffuse map's processing)
-uniform int uEnvMapSize;     //!< one edge's size of source environtment map's zero mipmap level
-uniform int uYCoeff;         //!< coefficient of Y controlling horizontal flip of cubemap
-uniform int uZCoeff;         //!< coefficient of Z controlling vertical flip of cubemap
+#else
+const int uSamplesNum = 256;
+#endif
 uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)
 
+#ifdef THE_TO_BAKE_DIFFUSE
+uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap
+uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap
+#endif
+
+#ifdef THE_TO_BAKE_SPECULAR
+uniform int   uCurrentLevel;        //!< current level of specular IBL map (ignored in case of diffuse map's processing)
+uniform float uEnvSolidAngleSource; //!< source solid angle sample computed from one edge's size of source environment map's zero mipmap level
+#endif
+
 //! Returns coordinates of point theNumber from Hammersley point set having size theSize.
 vec2 hammersley (in int theNumber,
                  in int theSize)
@@ -18,7 +28,7 @@ vec2 hammersley (in int theNumber,
   {
     if (aNumber > 0)
     {
-      aVanDerCorput += float(aNumber % 2) / float(aDenominator);
+      aVanDerCorput += mod(float(aNumber), 2.0) / float(aDenominator);
       aNumber /= 2;
       aDenominator *= 2;
     }
@@ -62,6 +72,8 @@ vec3 fromTangentSpace (in vec3 theVector,
   return anX * theVector.x + anY * theVector.y + theNormal * theVector.z;
 }
 
+#ifdef THE_TO_BAKE_DIFFUSE
+#if (__VERSION__ >= 120)
 const float aSHBasisFuncCoeffs[9] = float[9]
 (
   0.282095 * 0.282095,
@@ -74,7 +86,6 @@ const float aSHBasisFuncCoeffs[9] = float[9]
   0.315392 * 0.315392,
   0.546274 * 0.546274
 );
-
 const float aSHCosCoeffs[9] = float[9]
 (
   3.141593,
@@ -87,76 +98,129 @@ const float aSHCosCoeffs[9] = float[9]
   0.785398,
   0.785398
 );
+#else
+uniform float aSHBasisFuncCoeffs[9];
+uniform float aSHCosCoeffs[9];
+#endif
 
 //! Bakes diffuse IBL map's spherical harmonics coefficients.
 vec3 bakeDiffuseSH()
 {
-  int anIndex = int(gl_FragCoord.x);
-  vec3 aResult = vec3 (0.0);
+  int anId = int(gl_FragCoord.x);
+  float aCoef;
+#if (__VERSION__ >= 120)
+  aCoef = aSHCosCoeffs[anId] * aSHBasisFuncCoeffs[anId];
+#else
+  if      (anId == 0) { aCoef = aSHCosCoeffs[0] * aSHBasisFuncCoeffs[0]; }
+  else if (anId == 1) { aCoef = aSHCosCoeffs[1] * aSHBasisFuncCoeffs[1]; }
+  else if (anId == 2) { aCoef = aSHCosCoeffs[2] * aSHBasisFuncCoeffs[2]; }
+  else if (anId == 3) { aCoef = aSHCosCoeffs[3] * aSHBasisFuncCoeffs[3]; }
+  else if (anId == 4) { aCoef = aSHCosCoeffs[4] * aSHBasisFuncCoeffs[4]; }
+  else if (anId == 5) { aCoef = aSHCosCoeffs[5] * aSHBasisFuncCoeffs[5]; }
+  else if (anId == 6) { aCoef = aSHCosCoeffs[6] * aSHBasisFuncCoeffs[6]; }
+  else if (anId == 7) { aCoef = aSHCosCoeffs[7] * aSHBasisFuncCoeffs[7]; }
+  else                { aCoef = aSHCosCoeffs[8] * aSHBasisFuncCoeffs[8]; }
+#endif
+  vec3 aRes = vec3 (0.0);
   for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
   {
     vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum);
-    vec3 aDirection = sphereUniformSample (aHammersleyPoint);
-
-    vec3 aValue = occTextureCube (uEnvMap, cubemapVectorTransform (aDirection, uYCoeff, uZCoeff)).rgb;
-
-    float aBasisFunc[9];
-    aBasisFunc[0] = 1.0;
-
-    aBasisFunc[1] = aDirection.x;
-    aBasisFunc[2] = aDirection.y;
-    aBasisFunc[3] = aDirection.z;
-
-    aBasisFunc[4] = aDirection.x * aDirection.z;
-    aBasisFunc[5] = aDirection.y * aDirection.z;
-    aBasisFunc[6] = aDirection.x * aDirection.y;
-
-    aBasisFunc[7] = 3.0 * aDirection.z * aDirection.z - 1.0;
-    aBasisFunc[8] = aDirection.x * aDirection.x - aDirection.y * aDirection.y;
-
-    aResult += aValue * aBasisFunc[anIndex];
+    vec3 aDir = sphereUniformSample (aHammersleyPoint);
+
+    vec3 aVal = occTextureCube (uEnvMap, cubemapVectorTransform (aDir, uYCoeff, uZCoeff)).rgb;
+  #if (__VERSION__ >= 120)
+    float aFunc[9];
+    aFunc[0] = 1.0;
+
+    aFunc[1] = aDir.x;
+    aFunc[2] = aDir.y;
+    aFunc[3] = aDir.z;
+
+    aFunc[4] = aDir.x * aDir.z;
+    aFunc[5] = aDir.y * aDir.z;
+    aFunc[6] = aDir.x * aDir.y;
+
+    aFunc[7] = 3.0 * aDir.z * aDir.z - 1.0;
+    aFunc[8] = aDir.x * aDir.x - aDir.y * aDir.y;
+
+    aRes += aVal * aFunc[anId];
+  #else
+    if      (anId == 0) { aRes += aVal * 1.0; }
+    else if (anId == 1) { aRes += aVal * aDir.x; }
+    else if (anId == 2) { aRes += aVal * aDir.y; }
+    else if (anId == 3) { aRes += aVal * aDir.z; }
+    else if (anId == 4) { aRes += aVal * (aDir.x * aDir.z); }
+    else if (anId == 5) { aRes += aVal * (aDir.y * aDir.z); }
+    else if (anId == 6) { aRes += aVal * (aDir.x * aDir.y); }
+    else if (anId == 7) { aRes += aVal * (3.0 * aDir.z * aDir.z - 1.0); }
+    else                { aRes += aVal * (aDir.x * aDir.x - aDir.y * aDir.y); }
+  #endif
   }
 
-  aResult *= 4.0 * aSHCosCoeffs[anIndex] * aSHBasisFuncCoeffs[anIndex] / float(uSamplesNum);
-  return aResult;
+  return 4.0 * aRes * aCoef / float(uSamplesNum);
+}
+#endif
+
+#ifdef THE_TO_BAKE_SPECULAR
+//! Computes a single sample for specular IBL map.
+vec4 specularMapSample (in vec3  theNormal,
+                        in float theRoughness,
+                        in int   theNumber,
+                        in int   theSize)
+{
+  vec2 aHammersleyPoint = hammersley (theNumber, theSize);
+  vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));
+  float aHdotV = aHalf.z;
+  aHalf = fromTangentSpace (aHalf, theNormal);
+  vec3  aLight = -reflect (theNormal, aHalf);
+  float aNdotL = dot (aLight, theNormal);
+  if (aNdotL > 0.0)
+  {
+    float aSolidAngleSample = 1.0 / (float(theSize) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);
+    float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / uEnvSolidAngleSource);
+    return vec4 (occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL, aNdotL);
+  }
+  return vec4 (0.0);
 }
 
 //! Bakes specular IBL map.
 vec3 bakeSpecularMap (in vec3  theNormal,
                       in float theRoughness)
 {
-  vec3 aResult = vec3(0.0);
-  float aWeightSum = 0.0;
-  int aSamplesNum = (theRoughness == 0.0) ? 1 : uSamplesNum;
-  float aSolidAngleSource = 4.0 * PI / (6.0 * float(uEnvMapSize * uEnvMapSize));
-  for (int aSampleIter = 0; aSampleIter < aSamplesNum; ++aSampleIter)
+  vec4 aResult = vec4(0.0);
+  if (theRoughness == 0.0)
+  {
+    aResult = specularMapSample (theNormal, theRoughness, 0, 1);
+  }
+  else
   {
-    vec2 aHammersleyPoint = hammersley (aSampleIter, aSamplesNum);
-    vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));
-    float aHdotV = aHalf.z;
-    aHalf = fromTangentSpace (aHalf, theNormal);
-    vec3  aLight = -reflect (theNormal, aHalf);
-    float aNdotL = dot (aLight, theNormal);
-    if (aNdotL > 0.0)
+    for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)
     {
-      float aSolidAngleSample = 1.0 / (float(aSamplesNum) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);
-      float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / aSolidAngleSource);
-      aResult += occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL;
-      aWeightSum += aNdotL;
+      aResult += specularMapSample (theNormal, theRoughness, aSampleIter, uSamplesNum);
     }
   }
-  return aResult / aWeightSum;
+  return aResult.xyz / aResult.w;
 }
+#endif
 
 void main()
 {
   vec3 aViewDirection = normalize (ViewDirection);
-  if (occNbSpecIBLLevels == 0)
-  {
-    occSetFragColor (vec4 (bakeDiffuseSH (), 1.0));
-  }
-  else
-  {
-    occSetFragColor (vec4 (bakeSpecularMap (aViewDirection, float(uCurrentLevel) / float(occNbSpecIBLLevels - 1)), 1.0));
-  }
+#ifdef THE_TO_BAKE_DIFFUSE
+  vec4 aRes = vec4 (bakeDiffuseSH(), 1.0);
+#ifdef THE_TO_PACK_FLOAT
+  int aCompIndex = int(gl_FragCoord.y);
+  float aComp = aCompIndex == 0 ? aRes.x : (aCompIndex == 1 ? aRes.y : aRes.z);
+  int aFixedPrec = int(aComp * 2147483647.0);
+  int aFixedDiv1 = aFixedPrec / 256;
+  int aFixedDiv2 = aFixedDiv1 / 256;
+  int aFixedDiv3 = aFixedDiv2 / 256;
+  vec4 aPacked = vec4(float(aFixedPrec), float(aFixedDiv1), float(aFixedDiv2), float(aFixedDiv3));
+  aRes = fract (aPacked * (1.0 / 256.0));
+#endif
+  occFragColor = aRes;
+#else
+  float aRoughness = float(uCurrentLevel) / float(occNbSpecIBLLevels - 1);
+  occFragColor = vec4 (bakeSpecularMap (aViewDirection, aRoughness), 1.0);
+#endif
 }
index d9339aee25c85b7358422a9e6081d4381a0e3a3b..f8f8f31bde3afa56903e054a78ca10344b34bc1b 100644 (file)
@@ -4,32 +4,52 @@ uniform int uCurrentSide; //!< current side of cubemap
 uniform int uYCoeff;      //!< coefficient of Y controlling horizontal flip of cubemap
 uniform int uZCoeff;      //!< coefficient of Z controlling vertical flip of cubemap
 
-const mat2 cubemapDirectionMatrices[6] = mat2[]
-(
-  mat2 ( 0, -1, -1,  0),
-  mat2 ( 0,  1, -1,  0),
-  mat2 ( 0,  1,  1,  0),
-  mat2 ( 0,  1, -1,  0),
-  mat2 ( 1,  0,  0, -1),
-  mat2 (-1,  0,  0, -1)
-);
-
-//! Generates environment map fetching direction considering current index of side.
-vec3 cubemapBakingViewDirection (in int theSide,
-                                 in vec2 theScreenCoord)
-{
-  int anAxis = theSide / 2;
-  vec3 aDirection = vec3(0.0);
-  aDirection[anAxis] = float(-(int(theSide) % 2) * 2 + 1);
-  theScreenCoord = cubemapDirectionMatrices[theSide] * theScreenCoord;
-  aDirection[(anAxis + 1) % 3] = theScreenCoord.x;
-  aDirection[(anAxis + 2) % 3] = theScreenCoord.y;
-  return aDirection;
-}
-
 void main()
 {
-  ViewDirection = cubemapBakingViewDirection (uCurrentSide, occVertex.xy);
-  ViewDirection = cubemapVectorTransform (ViewDirection, uYCoeff, uZCoeff);
+  vec3 aDir;
+  vec2 aCoord;
+  if (uCurrentSide == 0)
+  {
+    aCoord = mat2( 0,-1,-1, 0) * occVertex.xy;
+    aDir.x = 1.0;
+    aDir.y = aCoord.x;
+    aDir.z = aCoord.y;
+  }
+  else if (uCurrentSide == 1)
+  {
+    aCoord = mat2( 0, 1,-1, 0) * occVertex.xy;
+    aDir.x = -1.0;
+    aDir.y = aCoord.x;
+    aDir.z = aCoord.y;
+  }
+  else if (uCurrentSide == 2)
+  {
+    aCoord = mat2( 0, 1, 1, 0) * occVertex.xy;
+    aDir.x = aCoord.y;
+    aDir.y = 1.0;
+    aDir.z = aCoord.x;
+  }
+  else if (uCurrentSide == 3)
+  {
+    aCoord = mat2( 0, 1,-1, 0) * occVertex.xy;
+    aDir.x = aCoord.y;
+    aDir.y = -1.0;
+    aDir.z = aCoord.x;
+  }
+  else if (uCurrentSide == 4)
+  {
+    aCoord = mat2( 1, 0, 0,-1) * occVertex.xy;
+    aDir.x = aCoord.x;
+    aDir.y = aCoord.y;
+    aDir.z = 1.0;
+  }
+  else //if (uCurrentSide == 5)
+  {
+    aCoord = mat2(-1, 0, 0,-1) * occVertex.xy;
+    aDir.x = aCoord.x;
+    aDir.y = aCoord.y;
+    aDir.z = -1.0;
+  }
+  ViewDirection = cubemapVectorTransform (aDir, uYCoeff, uZCoeff);
   gl_Position = vec4 (occVertex.xy, 0.0, 1.0);
 }
index c33fdf60c09c22518ab0c0a814b36f5b9f111ad3..bd3be983670d238ca898a9fd9ac98b53e92925d6 100644 (file)
@@ -146,44 +146,49 @@ static const char Shaders_Declarations_glsl[] =
   "// Light sources\n"
   "uniform               vec4 occLightAmbient;      //!< Cumulative ambient color\n"
   "#if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)\n"
+  "#if (THE_MAX_LIGHTS > 1)\n"
+  "  #define occLight_Index(theId) theId\n"
+  "#else\n"
+  "  #define occLight_Index(theId) 0\n"
+  "#endif\n"
   "uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sources\n"
   "\n"
   "//! Type of light source, int (see OccLightType enum).\n"
-  "#define occLight_Type(theId)              occLightSourcesTypes[theId]\n"
+  "#define occLight_Type(theId)              occLightSourcesTypes[occLight_Index(theId)]\n"
   "\n"
   "//! Specular intensity (equals to diffuse), vec3.\n"
-  "#define occLight_Specular(theId)          occLightSources[theId * 4 + 0].rgb\n"
+  "#define occLight_Specular(theId)          occLightSources[occLight_Index(theId) * 4 + 0].rgb\n"
   "\n"
   "//! Intensity of light source (>= 0), float.\n"
-  "#define occLight_Intensity(theId)         occLightSources[theId * 4 + 0].a\n"
+  "#define occLight_Intensity(theId)         occLightSources[occLight_Index(theId) * 4 + 0].a\n"
   "\n"
   "//! Is light a headlight, bool? DEPRECATED method.\n"
   "#define occLight_IsHeadlight(theId) false\n"
   "\n"
   "//! Position of specified light source or direction of directional light source, vec3.\n"
-  "#define occLight_Position(theId)          occLightSources[theId * 4 + 1].xyz\n"
+  "#define occLight_Position(theId)          occLightSources[occLight_Index(theId) * 4 + 1].xyz\n"
   "\n"
   "//! Direction of specified spot light source, vec3.\n"
-  "#define occLight_SpotDirection(theId)     occLightSources[theId * 4 + 2].xyz\n"
+  "#define occLight_SpotDirection(theId)     occLightSources[occLight_Index(theId) * 4 + 2].xyz\n"
   "\n"
   "//! Range on which point light source (positional or spot) can affect (>= 0), float.\n"
-  "#define occLight_Range(theId)             occLightSources[theId * 4 + 2].w\n"
+  "#define occLight_Range(theId)             occLightSources[occLight_Index(theId) * 4 + 2].w\n"
   "\n"
   "//! Maximum spread angle of the spot light (in radians), float.\n"
-  "#define occLight_SpotCutOff(theId)        occLightSources[theId * 4 + 3].z\n"
+  "#define occLight_SpotCutOff(theId)        occLightSources[occLight_Index(theId) * 4 + 3].z\n"
   "\n"
   "//! Attenuation of the spot light intensity (from 0 to 1), float.\n"
-  "#define occLight_SpotExponent(theId)      occLightSources[theId * 4 + 3].w\n"
+  "#define occLight_SpotExponent(theId)      occLightSources[occLight_Index(theId) * 4 + 3].w\n"
   "\n"
   "#if !defined(THE_IS_PBR)\n"
   "//! Diffuse intensity (equals to Specular), vec3.\n"
-  "#define occLight_Diffuse(theId)           occLightSources[theId * 4 + 0].rgb\n"
+  "#define occLight_Diffuse(theId)           occLightSources[occLight_Index(theId) * 4 + 0].rgb\n"
   "\n"
   "//! Const attenuation factor of positional light source, float.\n"
-  "#define occLight_ConstAttenuation(theId)  occLightSources[theId * 4 + 3].x\n"
+  "#define occLight_ConstAttenuation(theId)  occLightSources[occLight_Index(theId) * 4 + 3].x\n"
   "\n"
   "//! Linear attenuation factor of positional light source, float.\n"
-  "#define occLight_LinearAttenuation(theId) occLightSources[theId * 4 + 3].y\n"
+  "#define occLight_LinearAttenuation(theId) occLightSources[occLight_Index(theId) * 4 + 3].y\n"
   "#endif\n"
   "#endif\n"
   "\n"
index 1aff57dfba1e7f84a9bf87fb1aa87fb15ab127fb..aed61e598c5ba4c5d99c6828ce0a11312eedd036 100644 (file)
@@ -17,7 +17,7 @@ static const char Shaders_DirectionalLightShadow_glsl[] =
   "                                 in int  theId,\n"
   "                                 in vec3 theNormal)\n"
   "{\n"
-  "  vec4 aPosLightSpace = PosLightSpace[theId];\n"
+  "  vec4 aPosLightSpace = PosLightSpace[occLight_Index(theId)];\n"
   "  vec3 aLightDir = vec3 (occWorldViewMatrix * vec4 (occLight_Position (theId), 0.0));\n"
   "  vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w) * 0.5 + vec3 (0.5);\n"
   "  float aCurrentDepth = aProjCoords.z;\n"
index bc995ac8e7cc102e3fdad8bfd8207ad3d2ccbf22..183773b27834ec478e0a7f2bf550255ce5fce714 100644 (file)
@@ -3,13 +3,23 @@
 static const char Shaders_PBREnvBaking_fs[] =
   "THE_SHADER_IN vec3 ViewDirection; //!< direction of fetching from environment cubemap\n"
   "\n"
+  "#if (__VERSION__ >= 120)\n"
   "uniform int uSamplesNum;     //!< number of samples in Monte-Carlo integration\n"
-  "uniform int uCurrentLevel;   //!< current level of specular IBL map (ignored in case of diffuse map's processing)\n"
-  "uniform int uEnvMapSize;     //!< one edge's size of source environtment map's zero mipmap level\n"
-  "uniform int uYCoeff;         //!< coefficient of Y controlling horizontal flip of cubemap\n"
-  "uniform int uZCoeff;         //!< coefficient of Z controlling vertical flip of cubemap\n"
+  "#else\n"
+  "const int uSamplesNum = 256;\n"
+  "#endif\n"
   "uniform samplerCube uEnvMap; //!< source of baking (environment cubemap)\n"
   "\n"
+  "#ifdef THE_TO_BAKE_DIFFUSE\n"
+  "uniform int uYCoeff; //!< coefficient of Y controlling horizontal flip of cubemap\n"
+  "uniform int uZCoeff; //!< coefficient of Z controlling vertical flip of cubemap\n"
+  "#endif\n"
+  "\n"
+  "#ifdef THE_TO_BAKE_SPECULAR\n"
+  "uniform int   uCurrentLevel;        //!< current level of specular IBL map (ignored in case of diffuse map's processing)\n"
+  "uniform float uEnvSolidAngleSource; //!< source solid angle sample computed from one edge's size of source environment map's zero mipmap level\n"
+  "#endif\n"
+  "\n"
   "//! Returns coordinates of point theNumber from Hammersley point set having size theSize.\n"
   "vec2 hammersley (in int theNumber,\n"
   "                 in int theSize)\n"
@@ -21,7 +31,7 @@ static const char Shaders_PBREnvBaking_fs[] =
   "  {\n"
   "    if (aNumber > 0)\n"
   "    {\n"
-  "      aVanDerCorput += float(aNumber % 2) / float(aDenominator);\n"
+  "      aVanDerCorput += mod(float(aNumber), 2.0) / float(aDenominator);\n"
   "      aNumber /= 2;\n"
   "      aDenominator *= 2;\n"
   "    }\n"
@@ -65,6 +75,8 @@ static const char Shaders_PBREnvBaking_fs[] =
   "  return anX * theVector.x + anY * theVector.y + theNormal * theVector.z;\n"
   "}\n"
   "\n"
+  "#ifdef THE_TO_BAKE_DIFFUSE\n"
+  "#if (__VERSION__ >= 120)\n"
   "const float aSHBasisFuncCoeffs[9] = float[9]\n"
   "(\n"
   "  0.282095 * 0.282095,\n"
@@ -77,7 +89,6 @@ static const char Shaders_PBREnvBaking_fs[] =
   "  0.315392 * 0.315392,\n"
   "  0.546274 * 0.546274\n"
   ");\n"
-  "\n"
   "const float aSHCosCoeffs[9] = float[9]\n"
   "(\n"
   "  3.141593,\n"
@@ -90,76 +101,129 @@ static const char Shaders_PBREnvBaking_fs[] =
   "  0.785398,\n"
   "  0.785398\n"
   ");\n"
+  "#else\n"
+  "uniform float aSHBasisFuncCoeffs[9];\n"
+  "uniform float aSHCosCoeffs[9];\n"
+  "#endif\n"
   "\n"
   "//! Bakes diffuse IBL map's spherical harmonics coefficients.\n"
   "vec3 bakeDiffuseSH()\n"
   "{\n"
-  "  int anIndex = int(gl_FragCoord.x);\n"
-  "  vec3 aResult = vec3 (0.0);\n"
+  "  int anId = int(gl_FragCoord.x);\n"
+  "  float aCoef;\n"
+  "#if (__VERSION__ >= 120)\n"
+  "  aCoef = aSHCosCoeffs[anId] * aSHBasisFuncCoeffs[anId];\n"
+  "#else\n"
+  "  if      (anId == 0) { aCoef = aSHCosCoeffs[0] * aSHBasisFuncCoeffs[0]; }\n"
+  "  else if (anId == 1) { aCoef = aSHCosCoeffs[1] * aSHBasisFuncCoeffs[1]; }\n"
+  "  else if (anId == 2) { aCoef = aSHCosCoeffs[2] * aSHBasisFuncCoeffs[2]; }\n"
+  "  else if (anId == 3) { aCoef = aSHCosCoeffs[3] * aSHBasisFuncCoeffs[3]; }\n"
+  "  else if (anId == 4) { aCoef = aSHCosCoeffs[4] * aSHBasisFuncCoeffs[4]; }\n"
+  "  else if (anId == 5) { aCoef = aSHCosCoeffs[5] * aSHBasisFuncCoeffs[5]; }\n"
+  "  else if (anId == 6) { aCoef = aSHCosCoeffs[6] * aSHBasisFuncCoeffs[6]; }\n"
+  "  else if (anId == 7) { aCoef = aSHCosCoeffs[7] * aSHBasisFuncCoeffs[7]; }\n"
+  "  else                { aCoef = aSHCosCoeffs[8] * aSHBasisFuncCoeffs[8]; }\n"
+  "#endif\n"
+  "  vec3 aRes = vec3 (0.0);\n"
   "  for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)\n"
   "  {\n"
   "    vec2 aHammersleyPoint = hammersley (aSampleIter, uSamplesNum);\n"
-  "    vec3 aDirection = sphereUniformSample (aHammersleyPoint);\n"
-  "\n"
-  "    vec3 aValue = occTextureCube (uEnvMap, cubemapVectorTransform (aDirection, uYCoeff, uZCoeff)).rgb;\n"
-  "\n"
-  "    float aBasisFunc[9];\n"
-  "    aBasisFunc[0] = 1.0;\n"
-  "\n"
-  "    aBasisFunc[1] = aDirection.x;\n"
-  "    aBasisFunc[2] = aDirection.y;\n"
-  "    aBasisFunc[3] = aDirection.z;\n"
-  "\n"
-  "    aBasisFunc[4] = aDirection.x * aDirection.z;\n"
-  "    aBasisFunc[5] = aDirection.y * aDirection.z;\n"
-  "    aBasisFunc[6] = aDirection.x * aDirection.y;\n"
-  "\n"
-  "    aBasisFunc[7] = 3.0 * aDirection.z * aDirection.z - 1.0;\n"
-  "    aBasisFunc[8] = aDirection.x * aDirection.x - aDirection.y * aDirection.y;\n"
-  "\n"
-  "    aResult += aValue * aBasisFunc[anIndex];\n"
+  "    vec3 aDir = sphereUniformSample (aHammersleyPoint);\n"
+  "\n"
+  "    vec3 aVal = occTextureCube (uEnvMap, cubemapVectorTransform (aDir, uYCoeff, uZCoeff)).rgb;\n"
+  "  #if (__VERSION__ >= 120)\n"
+  "    float aFunc[9];\n"
+  "    aFunc[0] = 1.0;\n"
+  "\n"
+  "    aFunc[1] = aDir.x;\n"
+  "    aFunc[2] = aDir.y;\n"
+  "    aFunc[3] = aDir.z;\n"
+  "\n"
+  "    aFunc[4] = aDir.x * aDir.z;\n"
+  "    aFunc[5] = aDir.y * aDir.z;\n"
+  "    aFunc[6] = aDir.x * aDir.y;\n"
+  "\n"
+  "    aFunc[7] = 3.0 * aDir.z * aDir.z - 1.0;\n"
+  "    aFunc[8] = aDir.x * aDir.x - aDir.y * aDir.y;\n"
+  "\n"
+  "    aRes += aVal * aFunc[anId];\n"
+  "  #else\n"
+  "    if      (anId == 0) { aRes += aVal * 1.0; }\n"
+  "    else if (anId == 1) { aRes += aVal * aDir.x; }\n"
+  "    else if (anId == 2) { aRes += aVal * aDir.y; }\n"
+  "    else if (anId == 3) { aRes += aVal * aDir.z; }\n"
+  "    else if (anId == 4) { aRes += aVal * (aDir.x * aDir.z); }\n"
+  "    else if (anId == 5) { aRes += aVal * (aDir.y * aDir.z); }\n"
+  "    else if (anId == 6) { aRes += aVal * (aDir.x * aDir.y); }\n"
+  "    else if (anId == 7) { aRes += aVal * (3.0 * aDir.z * aDir.z - 1.0); }\n"
+  "    else                { aRes += aVal * (aDir.x * aDir.x - aDir.y * aDir.y); }\n"
+  "  #endif\n"
   "  }\n"
   "\n"
-  "  aResult *= 4.0 * aSHCosCoeffs[anIndex] * aSHBasisFuncCoeffs[anIndex] / float(uSamplesNum);\n"
-  "  return aResult;\n"
+  "  return 4.0 * aRes * aCoef / float(uSamplesNum);\n"
+  "}\n"
+  "#endif\n"
+  "\n"
+  "#ifdef THE_TO_BAKE_SPECULAR\n"
+  "//! Computes a single sample for specular IBL map.\n"
+  "vec4 specularMapSample (in vec3  theNormal,\n"
+  "                        in float theRoughness,\n"
+  "                        in int   theNumber,\n"
+  "                        in int   theSize)\n"
+  "{\n"
+  "  vec2 aHammersleyPoint = hammersley (theNumber, theSize);\n"
+  "  vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));\n"
+  "  float aHdotV = aHalf.z;\n"
+  "  aHalf = fromTangentSpace (aHalf, theNormal);\n"
+  "  vec3  aLight = -reflect (theNormal, aHalf);\n"
+  "  float aNdotL = dot (aLight, theNormal);\n"
+  "  if (aNdotL > 0.0)\n"
+  "  {\n"
+  "    float aSolidAngleSample = 1.0 / (float(theSize) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);\n"
+  "    float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / uEnvSolidAngleSource);\n"
+  "    return vec4 (occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL, aNdotL);\n"
+  "  }\n"
+  "  return vec4 (0.0);\n"
   "}\n"
   "\n"
   "//! Bakes specular IBL map.\n"
   "vec3 bakeSpecularMap (in vec3  theNormal,\n"
   "                      in float theRoughness)\n"
   "{\n"
-  "  vec3 aResult = vec3(0.0);\n"
-  "  float aWeightSum = 0.0;\n"
-  "  int aSamplesNum = (theRoughness == 0.0) ? 1 : uSamplesNum;\n"
-  "  float aSolidAngleSource = 4.0 * PI / (6.0 * float(uEnvMapSize * uEnvMapSize));\n"
-  "  for (int aSampleIter = 0; aSampleIter < aSamplesNum; ++aSampleIter)\n"
+  "  vec4 aResult = vec4(0.0);\n"
+  "  if (theRoughness == 0.0)\n"
+  "  {\n"
+  "    aResult = specularMapSample (theNormal, theRoughness, 0, 1);\n"
+  "  }\n"
+  "  else\n"
   "  {\n"
-  "    vec2 aHammersleyPoint = hammersley (aSampleIter, aSamplesNum);\n"
-  "    vec3 aHalf = importanceSample (aHammersleyPoint, occRoughness (theRoughness));\n"
-  "    float aHdotV = aHalf.z;\n"
-  "    aHalf = fromTangentSpace (aHalf, theNormal);\n"
-  "    vec3  aLight = -reflect (theNormal, aHalf);\n"
-  "    float aNdotL = dot (aLight, theNormal);\n"
-  "    if (aNdotL > 0.0)\n"
+  "    for (int aSampleIter = 0; aSampleIter < uSamplesNum; ++aSampleIter)\n"
   "    {\n"
-  "      float aSolidAngleSample = 1.0 / (float(aSamplesNum) * (occPBRDistribution (aHdotV, theRoughness) * 0.25 + 0.0001) + 0.0001);\n"
-  "      float aLod = (theRoughness == 0.0) ? 0.0 : 0.5 * log2 (aSolidAngleSample / aSolidAngleSource);\n"
-  "      aResult += occTextureCubeLod (uEnvMap, aLight, aLod).rgb * aNdotL;\n"
-  "      aWeightSum += aNdotL;\n"
+  "      aResult += specularMapSample (theNormal, theRoughness, aSampleIter, uSamplesNum);\n"
   "    }\n"
   "  }\n"
-  "  return aResult / aWeightSum;\n"
+  "  return aResult.xyz / aResult.w;\n"
   "}\n"
+  "#endif\n"
   "\n"
   "void main()\n"
   "{\n"
   "  vec3 aViewDirection = normalize (ViewDirection);\n"
-  "  if (occNbSpecIBLLevels == 0)\n"
-  "  {\n"
-  "    occSetFragColor (vec4 (bakeDiffuseSH (), 1.0));\n"
-  "  }\n"
-  "  else\n"
-  "  {\n"
-  "    occSetFragColor (vec4 (bakeSpecularMap (aViewDirection, float(uCurrentLevel) / float(occNbSpecIBLLevels - 1)), 1.0));\n"
-  "  }\n"
+  "#ifdef THE_TO_BAKE_DIFFUSE\n"
+  "  vec4 aRes = vec4 (bakeDiffuseSH(), 1.0);\n"
+  "#ifdef THE_TO_PACK_FLOAT\n"
+  "  int aCompIndex = int(gl_FragCoord.y);\n"
+  "  float aComp = aCompIndex == 0 ? aRes.x : (aCompIndex == 1 ? aRes.y : aRes.z);\n"
+  "  int aFixedPrec = int(aComp * 2147483647.0);\n"
+  "  int aFixedDiv1 = aFixedPrec / 256;\n"
+  "  int aFixedDiv2 = aFixedDiv1 / 256;\n"
+  "  int aFixedDiv3 = aFixedDiv2 / 256;\n"
+  "  vec4 aPacked = vec4(float(aFixedPrec), float(aFixedDiv1), float(aFixedDiv2), float(aFixedDiv3));\n"
+  "  aRes = fract (aPacked * (1.0 / 256.0));\n"
+  "#endif\n"
+  "  occFragColor = aRes;\n"
+  "#else\n"
+  "  float aRoughness = float(uCurrentLevel) / float(occNbSpecIBLLevels - 1);\n"
+  "  occFragColor = vec4 (bakeSpecularMap (aViewDirection, aRoughness), 1.0);\n"
+  "#endif\n"
   "}\n";
index 89a37cb50dff045a6dcdc25a17bb1ff907704728..1c004a5fc756325d70f96954074fdf58ca7d368a 100644 (file)
@@ -7,32 +7,52 @@ static const char Shaders_PBREnvBaking_vs[] =
   "uniform int uYCoeff;      //!< coefficient of Y controlling horizontal flip of cubemap\n"
   "uniform int uZCoeff;      //!< coefficient of Z controlling vertical flip of cubemap\n"
   "\n"
-  "const mat2 cubemapDirectionMatrices[6] = mat2[]\n"
-  "(\n"
-  "  mat2 ( 0, -1, -1,  0),\n"
-  "  mat2 ( 0,  1, -1,  0),\n"
-  "  mat2 ( 0,  1,  1,  0),\n"
-  "  mat2 ( 0,  1, -1,  0),\n"
-  "  mat2 ( 1,  0,  0, -1),\n"
-  "  mat2 (-1,  0,  0, -1)\n"
-  ");\n"
-  "\n"
-  "//! Generates environment map fetching direction considering current index of side.\n"
-  "vec3 cubemapBakingViewDirection (in int theSide,\n"
-  "                                 in vec2 theScreenCoord)\n"
-  "{\n"
-  "  int anAxis = theSide / 2;\n"
-  "  vec3 aDirection = vec3(0.0);\n"
-  "  aDirection[anAxis] = float(-(int(theSide) % 2) * 2 + 1);\n"
-  "  theScreenCoord = cubemapDirectionMatrices[theSide] * theScreenCoord;\n"
-  "  aDirection[(anAxis + 1) % 3] = theScreenCoord.x;\n"
-  "  aDirection[(anAxis + 2) % 3] = theScreenCoord.y;\n"
-  "  return aDirection;\n"
-  "}\n"
-  "\n"
   "void main()\n"
   "{\n"
-  "  ViewDirection = cubemapBakingViewDirection (uCurrentSide, occVertex.xy);\n"
-  "  ViewDirection = cubemapVectorTransform (ViewDirection, uYCoeff, uZCoeff);\n"
+  "  vec3 aDir;\n"
+  "  vec2 aCoord;\n"
+  "  if (uCurrentSide == 0)\n"
+  "  {\n"
+  "    aCoord = mat2( 0,-1,-1, 0) * occVertex.xy;\n"
+  "    aDir.x = 1.0;\n"
+  "    aDir.y = aCoord.x;\n"
+  "    aDir.z = aCoord.y;\n"
+  "  }\n"
+  "  else if (uCurrentSide == 1)\n"
+  "  {\n"
+  "    aCoord = mat2( 0, 1,-1, 0) * occVertex.xy;\n"
+  "    aDir.x = -1.0;\n"
+  "    aDir.y = aCoord.x;\n"
+  "    aDir.z = aCoord.y;\n"
+  "  }\n"
+  "  else if (uCurrentSide == 2)\n"
+  "  {\n"
+  "    aCoord = mat2( 0, 1, 1, 0) * occVertex.xy;\n"
+  "    aDir.x = aCoord.y;\n"
+  "    aDir.y = 1.0;\n"
+  "    aDir.z = aCoord.x;\n"
+  "  }\n"
+  "  else if (uCurrentSide == 3)\n"
+  "  {\n"
+  "    aCoord = mat2( 0, 1,-1, 0) * occVertex.xy;\n"
+  "    aDir.x = aCoord.y;\n"
+  "    aDir.y = -1.0;\n"
+  "    aDir.z = aCoord.x;\n"
+  "  }\n"
+  "  else if (uCurrentSide == 4)\n"
+  "  {\n"
+  "    aCoord = mat2( 1, 0, 0,-1) * occVertex.xy;\n"
+  "    aDir.x = aCoord.x;\n"
+  "    aDir.y = aCoord.y;\n"
+  "    aDir.z = 1.0;\n"
+  "  }\n"
+  "  else //if (uCurrentSide == 5)\n"
+  "  {\n"
+  "    aCoord = mat2(-1, 0, 0,-1) * occVertex.xy;\n"
+  "    aDir.x = aCoord.x;\n"
+  "    aDir.y = aCoord.y;\n"
+  "    aDir.z = -1.0;\n"
+  "  }\n"
+  "  ViewDirection = cubemapVectorTransform (aDir, uYCoeff, uZCoeff);\n"
   "  gl_Position = vec4 (occVertex.xy, 0.0, 1.0);\n"
   "}\n";