diff --git a/src/Graphic3d/Graphic3d_AspectFillArea3d.cxx b/src/Graphic3d/Graphic3d_AspectFillArea3d.cxx index ee15c53951..41d529fa9a 100644 --- a/src/Graphic3d/Graphic3d_AspectFillArea3d.cxx +++ b/src/Graphic3d/Graphic3d_AspectFillArea3d.cxx @@ -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) { diff --git a/src/Graphic3d/Graphic3d_AspectFillArea3d.hxx b/src/Graphic3d/Graphic3d_AspectFillArea3d.hxx index 48e2f8e024..06b905814f 100644 --- a/src/Graphic3d/Graphic3d_AspectFillArea3d.hxx +++ b/src/Graphic3d/Graphic3d_AspectFillArea3d.hxx @@ -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; diff --git a/src/OpenGl/OpenGl_BackgroundArray.cxx b/src/OpenGl/OpenGl_BackgroundArray.cxx index f760dcfc98..110512aad5 100644 --- a/src/OpenGl/OpenGl_BackgroundArray.cxx +++ b/src/OpenGl/OpenGl_BackgroundArray.cxx @@ -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); diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx index dc1bad5587..7c69ec36c1 100644 --- a/src/OpenGl/OpenGl_PrimitiveArray.cxx +++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -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 (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 (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 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()); - } - 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); + 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 OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor(); + aCtx->SetColor4fv (anInteriorColor); drawArray (theWorkspace, aFaceColors, hasColorAttrib); + + // 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 (myDrawMode <= GL_LINE_STRIP) - { - aCtx->BindTextures (aTextureBack); - } #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) diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx index 29000b66f6..e82b7858cc 100644 --- a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx +++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx @@ -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 OpenGl_MapOfShaderPrograms; #endif // _OpenGl_SetOfShaderPrograms_HeaderFile diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index b2f4ea940a..c1aa495f0f 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -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 diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index 71e5ebc424..d49691f372 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -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 diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx index 26dc423e9f..b9eff19c9b 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.cxx +++ b/src/OpenGl/OpenGl_ShaderProgram.cxx @@ -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 diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index dc33347509..15523f4bee 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -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 }; diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 930a32a2a5..d52acd1f7e 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -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 index 0000000000..40e4fc52c7 --- /dev/null +++ b/tests/v3d/glsl/outline1 @@ -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 index 0000000000..c932618984 --- /dev/null +++ b/tests/v3d/glsl/outline2 @@ -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