0024437: Visualization - silhouette edges based on OpenGL IR-WEEK9
authorasl <asl@opencascade.com>
Wed, 27 Feb 2019 22:36:32 +0000 (01:36 +0300)
committerapn <apn@opencascade.com>
Thu, 28 Feb 2019 17:25:51 +0000 (20:25 +0300)
Added new flag Graphic3d_AspectFillArea3d::ToDrawSilhouette() activating silhouette (outline) rendering.

The new feature can simulate fake HLR look-n-feel,
when combined with Aspect_IS_HIDDENLINE interior style (filling object with background color),
face boundary edges (with most continuity flag set to c2 or lower).

Silhouette GLSL program is very simple - it displaces model alongside vertex normal,
so that it is applicable only to smooth surfaces and closed volumes,
and produces visual artifacts at sharp corners, especially when face boundary is disabled.

OpenGl_SetOfShaderPrograms has been modified so that to reduce
dimensions of the grid of static size based on amount of program combinations.

OpenGl_PrimitiveArray no more allocates VBO resources if primitive array
is marked to be not drawn via interior style / line type / marker type.

12 files changed:
src/Graphic3d/Graphic3d_AspectFillArea3d.cxx
src/Graphic3d/Graphic3d_AspectFillArea3d.hxx
src/OpenGl/OpenGl_BackgroundArray.cxx
src/OpenGl/OpenGl_PrimitiveArray.cxx
src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_ShaderProgram.cxx
src/OpenGl/OpenGl_ShaderProgram.hxx
src/ViewerTest/ViewerTest.cxx
tests/v3d/glsl/outline1 [new file with mode: 0644]
tests/v3d/glsl/outline2 [new file with mode: 0644]

index ee15c53..41d529f 100644 (file)
@@ -35,6 +35,7 @@ Graphic3d_AspectFillArea3d::Graphic3d_AspectFillArea3d()
   myToSkipFirstEdge     (false),
   myToDistinguishMaterials (false),
   myToDrawEdges         (false),
+  myToDrawSilhouette    (false),
   myToSuppressBackFaces (true),
   myToMapTexture        (false)
 {
@@ -67,6 +68,7 @@ Graphic3d_AspectFillArea3d::Graphic3d_AspectFillArea3d (const Aspect_InteriorSty
   myToSkipFirstEdge     (false),
   myToDistinguishMaterials (false),
   myToDrawEdges         (false),
+  myToDrawSilhouette    (false),
   myToSuppressBackFaces (true),
   myToMapTexture        (false)
 {
index 48e2f8e..06b9058 100644 (file)
@@ -320,6 +320,12 @@ public:
   //! Set skip first triangle edge flag for drawing wireframe presentation of quads array split into triangles.
   void SetSkipFirstEdge (bool theToSkipFirstEdge) { myToSkipFirstEdge = theToSkipFirstEdge; }
 
+  //! Returns TRUE if silhouette (outline) should be drawn (with edge color and width); FALSE by default.
+  bool ToDrawSilhouette() const { return myToDrawSilhouette; }
+
+  //! Enables/disables drawing silhouette (outline).
+  void SetDrawSilhouette (bool theToDraw) { myToDrawSilhouette = theToDraw; }
+
 public:
 
   //! Returns the hatch type used when InteriorStyle is IS_HATCH
@@ -395,6 +401,7 @@ protected:
   bool                    myToSkipFirstEdge;
   bool                    myToDistinguishMaterials;
   bool                    myToDrawEdges;
+  bool                    myToDrawSilhouette;
   bool                    myToSuppressBackFaces;
   bool                    myToMapTexture;
 
index f760dcf..110512a 100644 (file)
@@ -38,6 +38,7 @@ OpenGl_BackgroundArray::OpenGl_BackgroundArray (const Graphic3d_TypeOfBackground
   myAttribs = new Graphic3d_Buffer (anAlloc);
 
   myDrawMode = GL_TRIANGLE_STRIP;
+  myIsFillType = true;
 
   myGradientParams.color1 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
   myGradientParams.color2 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
index dc1bad5..7c69ec3 100644 (file)
@@ -24,6 +24,7 @@
 #include <OpenGl_ShaderProgram.hxx>
 #include <OpenGl_Structure.hxx>
 #include <OpenGl_VertexBufferCompat.hxx>
+#include <OpenGl_View.hxx>
 #include <OpenGl_Workspace.hxx>
 #include <Graphic3d_TextureParams.hxx>
 #include <NCollection_AlignedAllocator.hxx>
@@ -773,38 +774,12 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
                                             ? theWorkspace->ApplyAspectMarker()
                                             : theWorkspace->AspectMarker();
 
-  // create VBOs on first render call
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
-  if (!myIsVboInit)
-  {
-    // compatibility - keep data to draw markers using display lists
-    Standard_Boolean toKeepData = Standard_False;
-    if (myDrawMode == GL_POINTS)
-    {
-      const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
-      const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
-      toKeepData = aSpriteNorm != NULL
-               &&  aSpriteNorm->IsDisplayList();
-    }
-  #if defined (GL_ES_VERSION_2_0)
-    processIndices (aCtx);
-  #endif
-    buildVBO (aCtx, toKeepData);
-    myIsVboInit = Standard_True;
-  }
-  else if ((!myAttribs.IsNull()
-         &&  myAttribs->IsMutable())
-        || (!myIndices.IsNull()
-         &&  myIndices->IsMutable()))
-  {
-    updateVBO (aCtx);
-  }
 
-  // Temporarily disable environment mapping
   Handle(OpenGl_TextureSet) aTextureBack;
   bool toDrawArray = true;
   int toDrawInteriorEdges = 0; // 0 - no edges, 1 - glsl edges, 2 - polygonMode
-  if (myDrawMode > GL_LINE_STRIP)
+  if (myIsFillType)
   {
     toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY;
     if (anAspectFace->Aspect()->ToDrawEdges())
@@ -832,17 +807,51 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
     #endif
     }
   }
-  else if (myDrawMode <= GL_LINE_STRIP)
+  else
   {
-    aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
     if (myDrawMode == GL_POINTS)
     {
-      toDrawArray = anAspectMarker->Aspect()->Type() != Aspect_TOM_EMPTY;
+      if (anAspectMarker->Aspect()->Type() == Aspect_TOM_EMPTY)
+      {
+        return;
+      }
     }
     else
     {
-      toDrawArray = anAspectLine->Aspect()->Type() != Aspect_TOL_EMPTY;
+      if (anAspectLine->Aspect()->Type() == Aspect_TOL_EMPTY)
+      {
+        return;
+      }
+    }
+
+    // Temporarily disable environment mapping
+    aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+  }
+
+  // create VBOs on first render call
+  if (!myIsVboInit)
+  {
+    // compatibility - keep data to draw markers using display lists
+    Standard_Boolean toKeepData = Standard_False;
+    if (myDrawMode == GL_POINTS)
+    {
+      const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
+      const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
+      toKeepData = aSpriteNorm != NULL
+               &&  aSpriteNorm->IsDisplayList();
     }
+  #if defined (GL_ES_VERSION_2_0)
+    processIndices (aCtx);
+  #endif
+    buildVBO (aCtx, toKeepData);
+    myIsVboInit = Standard_True;
+  }
+  else if ((!myAttribs.IsNull()
+         &&  myAttribs->IsMutable())
+        || (!myIndices.IsNull()
+         &&  myIndices->IsMutable()))
+  {
+    updateVBO (aCtx);
   }
 
   Graphic3d_TypeOfShadingModel aShadingModel = Graphic3d_TOSM_UNLIT;
@@ -932,35 +941,54 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
       aCtx->SetTextureMatrix (aCtx->ActiveTextures()->First()->Sampler()->Parameters());
     }
 
-    if (myDrawMode <= GL_LINE_STRIP)
+    const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
+                                      ?  myBounds->Colors
+                                      :  NULL;
+    if (!myIsFillType)
     {
       const OpenGl_Vec4& aLineColor = myDrawMode == GL_POINTS ? theWorkspace->MarkerColor() : theWorkspace->LineColor();
       aCtx->SetColor4fv (aLineColor);
-    }
-    else
-    {
-      const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
-      aCtx->SetColor4fv (anInteriorColor);
-    }
-    if (myDrawMode == GL_LINES
-     || myDrawMode == GL_LINE_STRIP)
-    {
-      aCtx->SetTypeOfLine (anAspectLine->Aspect()->Type());
-      aCtx->SetLineWidth  (anAspectLine->Aspect()->Width());
+      if (myDrawMode == GL_LINES
+       || myDrawMode == GL_LINE_STRIP)
+      {
+        aCtx->SetTypeOfLine (anAspectLine->Aspect()->Type());
+        aCtx->SetLineWidth  (anAspectLine->Aspect()->Width());
+      }
+
+      drawArray (theWorkspace, aFaceColors, hasColorAttrib);
+      aCtx->BindTextures (aTextureBack);
+      return;
     }
 
-    const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
-                                      ?  myBounds->Colors
-                                      :  NULL;
+    const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
+    aCtx->SetColor4fv (anInteriorColor);
     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
-  }
 
-  if (myDrawMode <= GL_LINE_STRIP)
-  {
-    aCtx->BindTextures (aTextureBack);
+    // draw outline - only closed triangulation with defined vertex normals can be drawn in this way
+    if (anAspectFace->Aspect()->ToDrawSilhouette()
+     && aCtx->ToCullBackFaces()
+     && aCtx->ShaderManager()->BindOutlineProgram())
+    {
+      const Graphic3d_Vec2i aViewSize (aCtx->Viewport()[2], aCtx->Viewport()[3]);
+      const Standard_Integer aMin = aViewSize.minComp();
+      const GLfloat anEdgeWidth  = (GLfloat )anAspectFace->Aspect()->EdgeWidth() * aCtx->LineWidthScale() / (GLfloat )aMin;
+      const GLfloat anOrthoScale = theWorkspace->View()->Camera()->IsOrthographic() ? (GLfloat )theWorkspace->View()->Camera()->Scale() : -1.0f;
+
+      const Handle(OpenGl_ShaderProgram)& anOutlineProgram = aCtx->ActiveProgram();
+      anOutlineProgram->SetUniform (aCtx, anOutlineProgram->GetStateLocation (OpenGl_OCCT_SILHOUETTE_THICKNESS), anEdgeWidth);
+      anOutlineProgram->SetUniform (aCtx, anOutlineProgram->GetStateLocation (OpenGl_OCCT_ORTHO_SCALE),          anOrthoScale);
+      aCtx->SetColor4fv (anAspectFace->Aspect()->EdgeColorRGBA());
+
+      aCtx->core11fwd->glCullFace (GL_FRONT);
+      drawArray (theWorkspace, NULL, false);
+
+      aCtx->core11fwd->glCullFace (GL_BACK);
+    }
   }
+
 #if !defined(GL_ES_VERSION_2_0)
-  else if (toDrawInteriorEdges == 2)
+  // draw triangulation edges using Polygon Mode
+  if (toDrawInteriorEdges == 2)
   {
     if (anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_HOLLOW
      && anAspectFace->Aspect()->EdgeLineType()  == Aspect_TOL_SOLID)
index 29000b6..e82b785 100644 (file)
@@ -26,7 +26,7 @@ enum OpenGl_ProgramOptions
   OpenGl_PO_Point           = 0x0001, //!< point marker
   OpenGl_PO_VertColor       = 0x0002, //!< per-vertex color
   OpenGl_PO_TextureRGB      = 0x0004, //!< handle RGB   texturing
-  OpenGl_PO_TextureA        = 0x0008, //!< handle Alpha texturing
+  OpenGl_PO_TextureA        = 0x0008, //!< handle Alpha texturing (point sprites only)
   OpenGl_PO_TextureEnv      = 0x0010, //!< handle environment map
   OpenGl_PO_StippleLine     = 0x0020, //!< stipple line
   OpenGl_PO_ClipPlanes1     = 0x0040, //!< handle 1 clipping plane
@@ -38,10 +38,27 @@ enum OpenGl_ProgramOptions
   OpenGl_PO_WriteOit        = 0x0800, //!< write coverage buffer for Blended Order-Independent Transparency
   //
   OpenGl_PO_NB              = 0x1000, //!< overall number of combinations
+  OpenGl_PO_HasTextures     = OpenGl_PO_TextureRGB|OpenGl_PO_TextureA,
   OpenGl_PO_NeedsGeomShader = OpenGl_PO_MeshEdges,
 };
 
 //! Alias to programs array of predefined length
+class OpenGl_SetOfPrograms : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTI_INLINE(OpenGl_SetOfPrograms, Standard_Transient)
+public:
+
+  //! Empty constructor
+  OpenGl_SetOfPrograms() {}
+
+  //! Access program by index
+  Handle(OpenGl_ShaderProgram)& ChangeValue (Standard_Integer theProgramBits) { return myPrograms[theProgramBits]; }
+
+protected:
+  Handle(OpenGl_ShaderProgram) myPrograms[OpenGl_PO_NB]; //!< programs array
+};
+
+//! Alias to 2D programs array of predefined length
 class OpenGl_SetOfShaderPrograms : public Standard_Transient
 {
   DEFINE_STANDARD_RTTI_INLINE(OpenGl_SetOfShaderPrograms, Standard_Transient)
@@ -50,19 +67,31 @@ public:
   //! Empty constructor
   OpenGl_SetOfShaderPrograms() {}
 
+  //! Constructor
+  OpenGl_SetOfShaderPrograms (const Handle(OpenGl_SetOfPrograms)& thePrograms)
+  {
+    for (Standard_Integer aSetIter = 0; aSetIter < Graphic3d_TypeOfShadingModel_NB - 1; ++aSetIter)
+    {
+      myPrograms[aSetIter] = thePrograms;
+    }
+  }
+
   //! Access program by index
   Handle(OpenGl_ShaderProgram)& ChangeValue (Graphic3d_TypeOfShadingModel theShadingModel,
                                              Standard_Integer theProgramBits)
   {
-    return myPrograms[theShadingModel][theProgramBits];
+    Handle(OpenGl_SetOfPrograms)& aSet = myPrograms[theShadingModel - 1];
+    if (aSet.IsNull())
+    {
+      aSet = new OpenGl_SetOfPrograms();
+    }
+    return aSet->ChangeValue (theProgramBits);
   }
 
 protected:
-  Handle(OpenGl_ShaderProgram) myPrograms[Graphic3d_TypeOfShadingModel_NB][OpenGl_PO_NB]; //!< programs array
+  Handle(OpenGl_SetOfPrograms) myPrograms[Graphic3d_TypeOfShadingModel_NB - 1]; //!< programs array, excluding Graphic3d_TOSM_UNLIT
 };
 
-DEFINE_STANDARD_HANDLE(OpenGl_SetOfShaderPrograms, Standard_Transient)
-
 typedef NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_SetOfShaderPrograms)> OpenGl_MapOfShaderPrograms;
 
 #endif // _OpenGl_SetOfShaderPrograms_HeaderFile
index b2f4ea9..c1aa495 100644 (file)
@@ -108,8 +108,8 @@ const char THE_FUNC_pointLight[] =
   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
   EOL"  }"
   EOL
-  EOL"Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
-  EOL"Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
+  EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
+  EOL"  Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
   EOL"}";
 
 //! Function computes contribution of spotlight source
@@ -294,6 +294,17 @@ EOL"                 : mix (occWireframeColor, getColor(), aMixVal);" // interio
 EOL"  return aMixColor;"
 EOL"}";
 
+//! Compute gl_Position vertex shader output.
+const char THE_VERT_gl_Position[] =
+EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;";
+
+//! Displace gl_Position alongside vertex normal for outline rendering.
+//! This code adds silhouette only for smooth surfaces of closed primitive, and produces visual artifacts on sharp edges.
+const char THE_VERT_gl_Position_OUTLINE[] =
+EOL"  float anOutlineDisp = occOrthoScale > 0.0 ? occOrthoScale : gl_Position.w;"
+EOL"  vec4  anOutlinePos  = occVertex + vec4 (occNormal * (occSilhouetteThickness * anOutlineDisp), 0.0);"
+EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * anOutlinePos;";
+
 #if !defined(GL_ES_VERSION_2_0)
 
   static const GLfloat THE_DEFAULT_AMBIENT[4]    = { 0.0f, 0.0f, 0.0f, 1.0f };
@@ -397,7 +408,7 @@ EOL"}";
 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
 : myFfpProgram (new OpenGl_ShaderProgramFFP()),
   myShadingModel (Graphic3d_TOSM_VERTEX),
-  myUnlitPrograms (new OpenGl_SetOfShaderPrograms()),
+  myUnlitPrograms (new OpenGl_SetOfPrograms()),
   myContext  (theContext),
   myHasLocalOrigin (Standard_False),
   myLastView (NULL)
@@ -422,7 +433,8 @@ void OpenGl_ShaderManager::clear()
 {
   myProgramList.Clear();
   myLightPrograms.Nullify();
-  myUnlitPrograms = new OpenGl_SetOfShaderPrograms();
+  myUnlitPrograms = new OpenGl_SetOfPrograms();
+  myOutlinePrograms.Nullify();
   myMapOfLightPrograms.Clear();
   myFontProgram.Nullify();
   myBlitProgram.Nullify();
@@ -536,7 +548,11 @@ void OpenGl_ShaderManager::switchLightPrograms()
   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
   if (aLights.IsNull())
   {
-    myLightPrograms = myUnlitPrograms;
+    if (!myMapOfLightPrograms.Find ("unlit", myLightPrograms))
+    {
+      myLightPrograms = new OpenGl_SetOfShaderPrograms (myUnlitPrograms);
+      myMapOfLightPrograms.Bind ("unlit", myLightPrograms);
+    }
     return;
   }
 
@@ -1288,12 +1304,12 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
 
-  TCollection_AsciiString aSrcVert =
-      EOL"void main()"
+  TCollection_AsciiString aSrcVert = TCollection_AsciiString()
+    + EOL"void main()"
       EOL"{"
       EOL"  TexCoord = occTexCoord.st;"
-      EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
-      EOL"}";
+    + THE_VERT_gl_Position
+    + EOL"}";
 
   TCollection_AsciiString
     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).a; }";
@@ -1499,7 +1515,7 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standar
   TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").a; }";
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core11 == NULL
-   && (theBits & OpenGl_PO_TextureA) != 0)
+   && (theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureA)
   {
     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").r; }";
   }
@@ -1509,20 +1525,6 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standar
   return aSrcGetAlpha;
 }
 
-namespace
-{
-
-  // =======================================================================
-  // function : textureUsed
-  // purpose  :
-  // =======================================================================
-  static bool textureUsed (const Standard_Integer theBits)
-  {
-    return (theBits & OpenGl_PO_TextureA) != 0 || (theBits & OpenGl_PO_TextureRGB) != 0;
-  }
-
-}
-
 // =======================================================================
 // function : defaultGlslVersion
 // purpose  :
@@ -1692,7 +1694,8 @@ TCollection_AsciiString OpenGl_ShaderManager::prepareGeomMainSrc (OpenGl_ShaderO
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram,
-                                                               const Standard_Integer        theBits)
+                                                               Standard_Integer theBits,
+                                                               Standard_Boolean theIsOutline)
 {
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
   TCollection_AsciiString aSrcVert, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcVertEndMain;
@@ -1707,14 +1710,14 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
   #endif
 
-    if ((theBits & OpenGl_PO_TextureRGB) != 0)
+    if ((theBits & OpenGl_PO_HasTextures) != 0)
     {
-      aSrcFragGetColor =
-        EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord "); }";
-    }
+      if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
+      {
+        aSrcFragGetColor =
+          EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord "); }";
+      }
 
-    if (textureUsed (theBits))
-    {
       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
 
     #if !defined(GL_ES_VERSION_2_0)
@@ -1746,7 +1749,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
     }
 
-    if ((theBits & OpenGl_PO_TextureRGB) != 0)
+    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
     {
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
@@ -1810,7 +1813,13 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     aProgramSrc->SetWeightOitOutput (true);
   }
 
-  if ((theBits & OpenGl_PO_StippleLine) != 0)
+  if (theIsOutline)
+  {
+    aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float occOrthoScale",          Graphic3d_TOS_VERTEX));
+    aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float occSilhouetteThickness", Graphic3d_TOS_VERTEX));
+    aSrcVertEndMain = THE_VERT_gl_Position_OUTLINE;
+  }
+  else if ((theBits & OpenGl_PO_StippleLine) != 0)
   {
     const Standard_Integer aBits = defaultGlslVersion (aProgramSrc, "unlit", theBits);
     if ((aBits & OpenGl_PO_StippleLine) != 0)
@@ -1840,7 +1849,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     + EOL"void main()"
       EOL"{"
     + aSrcVertExtraMain
-    + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
+    + THE_VERT_gl_Position
     + aSrcVertEndMain
     + EOL"}";
 
@@ -1858,7 +1867,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     + aSrcFragMainGetColor
     + EOL"}";
 
-  defaultGlslVersion (aProgramSrc, "unlit", theBits);
+  defaultGlslVersion (aProgramSrc, theIsOutline ? "outline" : "unlit", theBits);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
@@ -1883,7 +1892,7 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TColl
                                                                      const Standard_Integer theBits)
 {
   TCollection_AsciiString aSrcFragGetColor;
-  if ((theBits & OpenGl_PO_TextureA) != 0)
+  if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureA)
   {
     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
       EOL"vec4 getColor(void)"
@@ -1894,7 +1903,7 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TColl
       EOL"  return aColor;"
       EOL"}";
   }
-  else if ((theBits & OpenGl_PO_TextureRGB) != 0)
+  else if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
   {
     aSrcFragGetColor = TCollection_AsciiString() +
       EOL"vec4 getColor(void)"
@@ -2064,7 +2073,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
   #endif
 
-    if (textureUsed (theBits))
+    if ((theBits & OpenGl_PO_HasTextures) != 0)
     {
       #if !defined(GL_ES_VERSION_2_0)
         if (myContext->core11 != NULL
@@ -2079,7 +2088,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
   }
   else
   {
-    if ((theBits & OpenGl_PO_TextureRGB) != 0)
+    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
     {
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
@@ -2152,8 +2161,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
     + aSrcVertExtraMain
-    + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
-      EOL"}";
+    + THE_VERT_gl_Position
+    + EOL"}";
 
   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
@@ -2225,7 +2234,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
   #endif
 
-    if (textureUsed (theBits))
+    if ((theBits & OpenGl_PO_HasTextures) != 0)
     {
       #if !defined(GL_ES_VERSION_2_0)
         if (myContext->core11 != NULL
@@ -2240,7 +2249,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   }
   else
   {
-    if ((theBits & OpenGl_PO_TextureRGB) != 0)
+    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
     {
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
@@ -2316,8 +2325,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
     + EOL"  View          = vec3 (0.0, 0.0, 1.0);"
     + aSrcVertExtraMain
-    + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
-      EOL"}";
+    + THE_VERT_gl_Position
+    + EOL"}";
 
   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
index 71e5ebc..d49691f 100644 (file)
@@ -90,7 +90,8 @@ public:
                                     Standard_Boolean theEnableEnvMap,
                                     const Handle(OpenGl_ShaderProgram)& theCustomProgram)
   {
-    return BindFaceProgram (theTextures, theShadingModel, theAlphaMode, Aspect_IS_SOLID, theHasVertColor, theEnableEnvMap, false, theCustomProgram);
+    return BindFaceProgram (theTextures, theShadingModel, theAlphaMode, Aspect_IS_SOLID,
+                            theHasVertColor, theEnableEnvMap, false, theCustomProgram);
   }
 
   //! Bind program for filled primitives rendering
@@ -177,6 +178,27 @@ public:
     return bindProgramWithState (myFontProgram);
   }
 
+  //! Bind program for outline rendering
+  Standard_Boolean BindOutlineProgram()
+  {
+    if (myContext->caps->ffpEnable)
+    {
+      return false;
+    }
+
+    const Standard_Integer aBits = getProgramBits (Handle(OpenGl_TextureSet)(), Graphic3d_AlphaMode_Opaque, Aspect_IS_SOLID, false, false, false);
+    if (myOutlinePrograms.IsNull())
+    {
+      myOutlinePrograms = new OpenGl_SetOfPrograms();
+    }
+    Handle(OpenGl_ShaderProgram)& aProgram = myOutlinePrograms->ChangeValue (aBits);
+    if (aProgram.IsNull())
+    {
+      prepareStdProgramUnlit (aProgram, aBits, true);
+    }
+    return bindProgramWithState (aProgram);
+  }
+
   //! Bind program for FBO blit operation.
   Standard_Boolean BindFboBlitProgram()
   {
@@ -518,10 +540,10 @@ protected:
     {
       // If environment map is enabled lighting calculations are
       // not needed (in accordance with default OCCT behavior)
-      Handle(OpenGl_ShaderProgram)& aProgram = myUnlitPrograms->ChangeValue (Graphic3d_TOSM_UNLIT, theBits);
+      Handle(OpenGl_ShaderProgram)& aProgram = myUnlitPrograms->ChangeValue (theBits);
       if (aProgram.IsNull())
       {
-        prepareStdProgramUnlit (aProgram, theBits);
+        prepareStdProgramUnlit (aProgram, theBits, false);
       }
       return aProgram;
     }
@@ -551,7 +573,8 @@ protected:
 
   //! Prepare standard GLSL program without lighting.
   Standard_EXPORT Standard_Boolean prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram,
-                                                           const Standard_Integer        theBits);
+                                                           Standard_Integer theBits,
+                                                           Standard_Boolean theIsOutline = false);
 
   //! Prepare standard GLSL program with lighting.
   Standard_Boolean prepareStdProgramLight (Handle(OpenGl_ShaderProgram)& theProgram,
@@ -560,7 +583,7 @@ protected:
   {
     switch (theShadingModel)
     {
-      case Graphic3d_TOSM_UNLIT:    return prepareStdProgramUnlit  (theProgram, theBits);
+      case Graphic3d_TOSM_UNLIT:    return prepareStdProgramUnlit  (theProgram, theBits, false);
       case Graphic3d_TOSM_FACET:    return prepareStdProgramPhong  (theProgram, theBits, true);
       case Graphic3d_TOSM_VERTEX:   return prepareStdProgramGouraud(theProgram, theBits);
       case Graphic3d_TOSM_DEFAULT:
@@ -674,7 +697,8 @@ protected:
   Graphic3d_TypeOfShadingModel       myShadingModel;       //!< lighting shading model
   OpenGl_ShaderProgramList           myProgramList;        //!< The list of shader programs
   Handle(OpenGl_SetOfShaderPrograms) myLightPrograms;      //!< pointer to active lighting programs matrix
-  Handle(OpenGl_SetOfShaderPrograms) myUnlitPrograms;      //!< programs matrix without  lighting
+  Handle(OpenGl_SetOfPrograms)       myUnlitPrograms;      //!< programs matrix without lighting
+  Handle(OpenGl_SetOfPrograms)       myOutlinePrograms;    //!< programs matrix without lighting for outline presentation
   Handle(OpenGl_ShaderProgram)       myFontProgram;        //!< standard program for textured text
   Handle(OpenGl_ShaderProgram)       myBlitProgram;        //!< standard program for FBO blit emulation
   Handle(OpenGl_ShaderProgram)       myBoundBoxProgram;    //!< standard program for bounding box
index 26dc423..b9eff19 100755 (executable)
@@ -83,6 +83,9 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
   "occLineFeather",        // OpenGl_OCCT_LINE_FEATHER
   "occWireframeColor",     // OpenGl_OCCT_WIREFRAME_COLOR
   "occIsQuadMode",         // OpenGl_OCCT_QUAD_MODE_STATE
+
+  "occOrthoScale",         // OpenGl_OCCT_ORTHO_SCALE
+  "occSilhouetteThickness" // OpenGl_OCCT_SILHOUETTE_THICKNESS
 };
 
 namespace
index dc33347..15523f4 100755 (executable)
@@ -82,6 +82,10 @@ enum OpenGl_StateVariable
   OpenGl_OCCT_WIREFRAME_COLOR,
   OpenGl_OCCT_QUAD_MODE_STATE,
 
+  // Parameters of outline (silhouette) shader
+  OpenGl_OCCT_ORTHO_SCALE,
+  OpenGl_OCCT_SILHOUETTE_THICKNESS,
+
   // DON'T MODIFY THIS ITEM (insert new items before it)
   OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES
 };
index 930a32a..d52acd1 100644 (file)
@@ -1587,6 +1587,8 @@ struct ViewerTest_AspectsChangeSet
   Standard_Integer             ToSetInterior;
   Aspect_InteriorStyle         InteriorStyle;
 
+  Standard_Integer             ToSetDrawSilhouette;
+
   Standard_Integer             ToSetDrawEdges;
   Standard_Integer             ToSetQuadEdges;
 
@@ -1648,6 +1650,7 @@ struct ViewerTest_AspectsChangeSet
     ShadingModel               (Graphic3d_TOSM_DEFAULT),
     ToSetInterior              (0),
     InteriorStyle              (Aspect_IS_SOLID),
+    ToSetDrawSilhouette (0),
     ToSetDrawEdges    (0),
     ToSetQuadEdges    (0),
     ToSetEdgeColor    (0),
@@ -1680,6 +1683,7 @@ struct ViewerTest_AspectsChangeSet
         && ToSetHatch             == 0
         && ToSetShadingModel      == 0
         && ToSetInterior          == 0
+        && ToSetDrawSilhouette    == 0
         && ToSetDrawEdges         == 0
         && ToSetQuadEdges         == 0
         && ToSetEdgeColor         == 0
@@ -1955,6 +1959,15 @@ struct ViewerTest_AspectsChangeSet
         }
       }
     }
+    if (ToSetDrawSilhouette != 0)
+    {
+      if (ToSetDrawSilhouette != -1
+       || theDrawer->HasOwnShadingAspect())
+      {
+        toRecompute = theDrawer->SetupOwnShadingAspect (aDefDrawer) || toRecompute;
+        theDrawer->ShadingAspect()->Aspect()->SetDrawSilhouette (ToSetDrawSilhouette == 1);
+      }
+    }
     if (ToSetDrawEdges != 0)
     {
       if (ToSetDrawEdges != -1
@@ -2886,6 +2899,22 @@ static Standard_Integer VAspects (Draw_Interpretor& /*theDI*/,
       aChangeSet->ToSetInterior = -1;
       aChangeSet->InteriorStyle = Aspect_IS_SOLID;
     }
+    else if (anArg == "-setdrawoutline"
+          || anArg == "-setdrawsilhouette"
+          || anArg == "-setoutline"
+          || anArg == "-setsilhouette"
+          || anArg == "-outline"
+          || anArg == "-outlined"
+          || anArg == "-silhouette")
+    {
+      bool toDrawOutline = true;
+      if (anArgIter + 1 < theArgNb
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toDrawOutline))
+      {
+        ++anArgIter;
+      }
+      aChangeSet->ToSetDrawSilhouette = toDrawOutline ? 1 : -1;
+    }
     else if (anArg == "-setdrawedges"
           || anArg == "-setdrawedge"
           || anArg == "-drawedges"
@@ -2974,6 +3003,7 @@ static Standard_Integer VAspects (Draw_Interpretor& /*theDI*/,
       aChangeSet->ShadingModel = Graphic3d_TOSM_DEFAULT;
       aChangeSet->ToSetInterior = -1;
       aChangeSet->InteriorStyle = Aspect_IS_SOLID;
+      aChangeSet->ToSetDrawSilhouette = -1;
       aChangeSet->ToSetDrawEdges = -1;
       aChangeSet->ToSetQuadEdges = -1;
       aChangeSet->ToSetEdgeColor = -1;
@@ -6193,6 +6223,7 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
       "\n\t\t:          [-setFaceBoundaryDraw {0|1}] [-setMostContinuity {c0|c1|c2|c3|cn}"
       "\n\t\t:          [-setFaceBoundaryWidth LineWidth] [-setFaceBoundaryColor R G B] [-setFaceBoundaryType LineType]"
       "\n\t\t:          [-setDrawEdges {0|1}] [-setEdgeType LineType] [-setEdgeColor R G B] [-setQuadEdges {0|1}]"
+      "\n\t\t:          [-setDrawSilhouette {0|1}]"
       "\n\t\t:          [-setAlphaMode {opaque|mask|blend|blendauto} [alphaCutOff=0.5]]"
       "\n\t\t: Manage presentation properties of all, selected or named objects."
       "\n\t\t: When -subshapes is specified than following properties will be"
diff --git a/tests/v3d/glsl/outline1 b/tests/v3d/glsl/outline1
new file mode 100644 (file)
index 0000000..40e4fc5
--- /dev/null
@@ -0,0 +1,25 @@
+puts "========"
+puts "0024437: Visualization - silhouette edges based on OpenGL"
+puts "Draw box and sphere primitives"
+puts "========"
+puts ""
+
+pload MODELING VISUALIZATION
+
+vclear
+vinit View1
+vsetcolorbg 220 220 220
+#vsetgradientbg 180 200 255 180 180 180 2
+vaxo
+
+psphere s 1.0
+box b 2 -2 -2 1 2 3
+
+vdisplay -dispMode 1 b s
+vfit
+
+vaspects b s -setDrawSilhouette 1 -setEdgeColor RED -setEdgeWidth 4 -setFaceBoundaryDraw 1 -setFaceBoundaryColor BLUE1 -setFaceBoundaryWidth 1 -setInteriorStyle HIDDENLINE
+vdump $::imagedir/${::casename}_0.png
+
+vaspects b s -setDrawSilhouette 1 -setEdgeColor RED -setEdgeWidth 4 -setFaceBoundaryDraw 1 -setFaceBoundaryColor RED   -setFaceBoundaryWidth 4 -setInteriorStyle HIDDENLINE
+vdump $::imagedir/${::casename}_1.png
diff --git a/tests/v3d/glsl/outline2 b/tests/v3d/glsl/outline2
new file mode 100644 (file)
index 0000000..c932618
--- /dev/null
@@ -0,0 +1,31 @@
+puts "========"
+puts "0024437: Visualization - silhouette edges based on OpenGL"
+puts "Draw bottle sample"
+puts "========"
+puts ""
+
+pload MODELING VISUALIZATION
+
+# test for creation of bottle as in tutorial (script is in samples)
+source $env(CSF_OCCTSamplesPath)/tcl/bottle.tcl
+
+vsetcolorbg 255 255 255
+vzbufftrihedron -type wireframe -colorLabels BLACK
+vaspects bottle -setDrawSilhouette 1 -setEdgeColor BLACK -setFaceBoundaryDraw 1 -setMostContinuity c0 -setFaceBoundaryColor BLACK -setInteriorStyle HIDDENLINE 
+vrenderparams -rendScale 2
+
+vcamera -ortho
+vfit
+vaspects bottle -setDrawSilhouette 0
+vdump $::imagedir/${::casename}_ortho0.png
+
+vaspects bottle -setDrawSilhouette 1
+vdump $::imagedir/${::casename}_ortho1.png
+
+vcamera -persp
+vfit
+vaspects bottle -setDrawSilhouette 0
+vdump $::imagedir/${::casename}_persp0.png
+
+vaspects bottle -setDrawSilhouette 1
+vdump $::imagedir/${::casename}_persp1.png