0028069: Visualization, TKOpenGl - handle flat shading model within GLSL programs
authorkgv <kgv@opencascade.com>
Sun, 10 Sep 2017 14:06:19 +0000 (17:06 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 28 Sep 2017 07:36:05 +0000 (10:36 +0300)
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
tests/v3d/glsl/flat_fuse1 [new file with mode: 0644]

index 494ca04..790be6e 100644 (file)
@@ -152,6 +152,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   atiMem (Standard_False),
   nvxMem (Standard_False),
   oesSampleVariables (Standard_False),
+  oesStdDerivatives (Standard_False),
   mySharedResources (new OpenGl_ResourcesMap()),
   myDelayed         (new OpenGl_DelayReleaseMap()),
   myUnusedResources (new OpenGl_ResourcesStack()),
@@ -1412,6 +1413,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
                                                                          : OpenGl_FeatureNotAvailable;
 
   oesSampleVariables = CheckExtension ("GL_OES_sample_variables");
+  oesStdDerivatives  = CheckExtension ("GL_OES_standard_derivatives");
   hasSampleVariables = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
                        oesSampleVariables ? OpenGl_FeatureInExtensions
                                           : OpenGl_FeatureNotAvailable;
index 018fa46..58d150f 100644 (file)
@@ -823,6 +823,7 @@ public: //! @name extensions
   Standard_Boolean       atiMem;             //!< GL_ATI_meminfo
   Standard_Boolean       nvxMem;             //!< GL_NVX_gpu_memory_info
   Standard_Boolean       oesSampleVariables; //!< GL_OES_sample_variables
+  Standard_Boolean       oesStdDerivatives;  //!< GL_OES_standard_derivatives
 
 public: //! @name public properties tracking current state
 
index e01e151..1867cc7 100644 (file)
@@ -479,7 +479,14 @@ Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
 // =======================================================================
 void OpenGl_ShaderManager::switchLightPrograms()
 {
-  TCollection_AsciiString aKey (myShadingModel == Graphic3d_TOSM_FRAGMENT ? "p_" : "g_");
+  TCollection_AsciiString aKey;
+  switch (myShadingModel)
+  {
+    case Graphic3d_TOSM_NONE:     aKey = "c_"; break;
+    case Graphic3d_TOSM_FACET:    aKey = "f_"; break;
+    case Graphic3d_TOSM_VERTEX:   aKey = "g_"; break;
+    case Graphic3d_TOSM_FRAGMENT: aKey = "p_"; break;
+  }
   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
   if (aLights != NULL)
   {
@@ -1847,9 +1854,17 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
-                                                               const Standard_Integer        theBits)
+                                                               const Standard_Integer        theBits,
+                                                               const Standard_Boolean        theIsFlatNormal)
 {
   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
+#if defined(GL_ES_VERSION_2_0)
+  const bool isFlatNormal = theIsFlatNormal
+                         && (myContext->IsGlGreaterEqual (3, 0)
+                          || myContext->oesStdDerivatives);
+#else
+  const bool isFlatNormal = theIsFlatNormal;
+#endif
 
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain;
@@ -1920,20 +1935,22 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   }
 
   aSrcVert = TCollection_AsciiString()
-    + THE_FUNC_transformNormal
+    + (isFlatNormal ? "" : THE_FUNC_transformNormal)
     + EOL
       EOL"THE_SHADER_OUT vec4 PositionWorld;"
       EOL"THE_SHADER_OUT vec4 Position;"
-      EOL"THE_SHADER_OUT vec3 Normal;"
       EOL"THE_SHADER_OUT vec3 View;"
-      EOL
+    + (isFlatNormal ? ""
+    : EOL"THE_SHADER_OUT vec3 Normal;")
+    + EOL
     + aSrcVertExtraOut
     + EOL"void main()"
       EOL"{"
       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
-      EOL"  Normal        = transformNormal (occNormal);"
-      EOL"  View          = vec3 (0.0, 0.0, 1.0);"
+    + (isFlatNormal ? ""
+    : EOL"  Normal        = transformNormal (occNormal);")
+    + EOL"  View          = vec3 (0.0, 0.0, 1.0);"
     + aSrcVertExtraMain
     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
       EOL"}";
@@ -1942,8 +1959,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   aSrcFrag = TCollection_AsciiString()
     + EOL"THE_SHADER_IN vec4 PositionWorld;"
       EOL"THE_SHADER_IN vec4 Position;"
-      EOL"THE_SHADER_IN vec3 Normal;"
       EOL"THE_SHADER_IN vec3 View;"
+    + (isFlatNormal
+    ? EOL"vec3 Normal;"
+    : EOL"THE_SHADER_IN vec3 Normal;")
     + EOL
     + aSrcFragExtraOut
     + aSrcFragGetVertColor
@@ -1953,6 +1972,9 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
       EOL"void main()"
       EOL"{"
     + aSrcFragExtraMain
+    + (isFlatNormal
+    ? EOL"  Normal = normalize (cross (dFdx (Position.xyz / Position.w), dFdy (Position.xyz / Position.w)));"
+    : "")
     + EOL"  occFragColor = getColor();"
     + aSrcFragWriteOit
     + EOL"}";
@@ -1967,6 +1989,19 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   {
     aProgramSrc->SetHeader ("#version 300 es");
   }
+  else if (isFlatNormal)
+  {
+    if (myContext->oesStdDerivatives)
+    {
+      aProgramSrc->SetHeader ("#extension GL_OES_standard_derivatives : enable");
+    }
+    else
+    {
+      myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+                              GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                              "Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension.");
+    }
+  }
 #endif
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
index 9e5d2f7..8e68cd3 100644 (file)
@@ -423,9 +423,14 @@ protected:
   Standard_Boolean prepareStdProgramLight (Handle(OpenGl_ShaderProgram)& theProgram,
                                            const Standard_Integer        theBits)
   {
-    return myShadingModel == Graphic3d_TOSM_FRAGMENT
-         ? prepareStdProgramPhong   (theProgram, theBits)
-         : prepareStdProgramGouraud (theProgram, theBits);
+    switch (myShadingModel)
+    {
+      case Graphic3d_TOSM_NONE:     return prepareStdProgramFlat   (theProgram, theBits);
+      case Graphic3d_TOSM_FACET:    return prepareStdProgramPhong  (theProgram, theBits, true);
+      case Graphic3d_TOSM_VERTEX:   return prepareStdProgramGouraud(theProgram, theBits);
+      case Graphic3d_TOSM_FRAGMENT: return prepareStdProgramPhong  (theProgram, theBits, false);
+    }
+    return false;
   }
 
   //! Prepare standard GLSL program with per-vertex lighting.
@@ -433,8 +438,10 @@ protected:
                                                              const Standard_Integer        theBits);
 
   //! Prepare standard GLSL program with per-pixel lighting.
+  //! @param theIsFlatNormal when TRUE, the Vertex normals will be ignored and Face normal will be computed instead
   Standard_EXPORT Standard_Boolean prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
-                                                           const Standard_Integer        theBits);
+                                                           const Standard_Integer        theBits,
+                                                           const Standard_Boolean        theIsFlatNormal = false);
 
   //! Define computeLighting GLSL function depending on current lights configuration
   //! @param theHasVertColor flag to use getVertColor() instead of Ambient and Diffuse components of active material
diff --git a/tests/v3d/glsl/flat_fuse1 b/tests/v3d/glsl/flat_fuse1
new file mode 100644 (file)
index 0000000..19dd37f
--- /dev/null
@@ -0,0 +1,22 @@
+puts "========"
+puts "0028069: Visualization, TKOpenGl - handle flat shading model within GLSL programs"
+puts "========"
+
+vclear
+vclose ALL
+vinit View1
+vviewparams -scale 551.55 -proj 0.85 -0.16 0.51 -up -0.41 0.41 0.82 -at 0.55 0.55 0.55
+
+restore [locate_data_file occ/fuse.brep] f
+tclean f
+vdefaults -absDefl 0.5
+vdisplay -dispMode 1 f
+
+# setup lights
+vlight clear
+vlight add ambient                color WHITE
+vlight add directional dir  1 0 0 color GREEN headlight 1
+vlight add directional dir -1 0 0 color RED1  headlight 1
+
+vrenderparams -shadingModel flat
+vdump $::imagedir/${::casename}.png