From 653a75c4e15da54551ed2ae5a789033185692b8d Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Tue, 29 Oct 2024 12:22:13 +1100 Subject: [PATCH 1/9] Introduce geometry shader for physical point cloud points --- src/Graphic3d/Graphic3d_Aspects.cxx | 1 + src/Graphic3d/Graphic3d_Aspects.hxx | 10 ++ src/Graphic3d/Graphic3d_ShaderFlags.hxx | 8 +- src/Graphic3d/Graphic3d_ShaderManager.cxx | 179 ++++++++++++++++------ src/Graphic3d/Graphic3d_ShaderObject.cxx | 27 +++- src/Graphic3d/Graphic3d_ShaderObject.hxx | 5 +- src/OpenGl/OpenGl_AspectsSprite.cxx | 11 +- src/OpenGl/OpenGl_AspectsSprite.hxx | 6 + src/OpenGl/OpenGl_PrimitiveArray.cxx | 2 +- src/OpenGl/OpenGl_ShaderManager.cxx | 6 + src/OpenGl/OpenGl_ShaderManager.hxx | 1 + 11 files changed, 192 insertions(+), 64 deletions(-) diff --git a/src/Graphic3d/Graphic3d_Aspects.cxx b/src/Graphic3d/Graphic3d_Aspects.cxx index b9420a8203..82f621efe2 100644 --- a/src/Graphic3d/Graphic3d_Aspects.cxx +++ b/src/Graphic3d/Graphic3d_Aspects.cxx @@ -35,6 +35,7 @@ Graphic3d_Aspects::Graphic3d_Aspects() myLinePattern (0xFFFF), myMarkerType (Aspect_TOM_POINT), myMarkerScale (1.0f), + myMarkerPhysical (false), myTextStyle (Aspect_TOST_NORMAL), myTextDisplayType (Aspect_TODT_NORMAL), myTextFontAspect (Font_FontAspect_Regular), diff --git a/src/Graphic3d/Graphic3d_Aspects.hxx b/src/Graphic3d/Graphic3d_Aspects.hxx index c438255cd9..e336f1a1bb 100644 --- a/src/Graphic3d/Graphic3d_Aspects.hxx +++ b/src/Graphic3d/Graphic3d_Aspects.hxx @@ -324,6 +324,14 @@ public: myMarkerScale = theScale; } + //! Whether the marker is rendered as a physical sphere in view space + Standard_Boolean MarkerPhysical() const { return myMarkerPhysical; } + + void SetMarkerPhysical (const Standard_Boolean theMarkerPhysical) + { + myMarkerPhysical = theMarkerPhysical; + } + //! Returns marker's image texture. //! Could be null handle if marker aspect has been initialized as default type of marker. const Handle(Graphic3d_MarkerImage)& MarkerImage() const { return myMarkerImage; } @@ -509,6 +517,7 @@ public: && myLinePattern == theOther.myLinePattern && myMarkerType == theOther.myMarkerType && myMarkerScale == theOther.myMarkerScale + && myMarkerPhysical == theOther.myMarkerPhysical && myHatchStyle == theOther.myHatchStyle && myTextFont == theOther.myTextFont && myPolygonOffset == theOther.myPolygonOffset @@ -580,6 +589,7 @@ protected: Aspect_TypeOfMarker myMarkerType; Standard_ShortReal myMarkerScale; + Standard_Boolean myMarkerPhysical; Aspect_TypeOfStyleText myTextStyle; Aspect_TypeOfDisplayText myTextDisplayType; diff --git a/src/Graphic3d/Graphic3d_ShaderFlags.hxx b/src/Graphic3d/Graphic3d_ShaderFlags.hxx index 125155d212..0b3b7f379c 100644 --- a/src/Graphic3d/Graphic3d_ShaderFlags.hxx +++ b/src/Graphic3d/Graphic3d_ShaderFlags.hxx @@ -35,11 +35,13 @@ enum Graphic3d_ShaderFlags Graphic3d_ShaderFlags_AlphaTest = 0x0400, //!< discard fragment by alpha test (defined by cutoff value) Graphic3d_ShaderFlags_WriteOit = 0x0800, //!< write coverage buffer for Blended Order-Independent Transparency Graphic3d_ShaderFlags_OitDepthPeeling = 0x1000, //!< handle Depth Peeling OIT + Graphic3d_ShaderFlags_PointCircle = 0x2000, //!< output points as circle billboards with diameter (gl_PointSize) instead // - Graphic3d_ShaderFlags_NB = 0x2000, //!< overall number of combinations - Graphic3d_ShaderFlags_IsPoint = Graphic3d_ShaderFlags_PointSimple|Graphic3d_ShaderFlags_PointSprite|Graphic3d_ShaderFlags_PointSpriteA, + Graphic3d_ShaderFlags_NB = 0x4000, //!< overall number of combinations + Graphic3d_ShaderFlags_IsPoint = Graphic3d_ShaderFlags_PointSimple|Graphic3d_ShaderFlags_PointSprite| + Graphic3d_ShaderFlags_PointSpriteA|Graphic3d_ShaderFlags_PointCircle, Graphic3d_ShaderFlags_HasTextures = Graphic3d_ShaderFlags_TextureRGB|Graphic3d_ShaderFlags_TextureEnv, - Graphic3d_ShaderFlags_NeedsGeomShader = Graphic3d_ShaderFlags_MeshEdges, + Graphic3d_ShaderFlags_NeedsGeomShader = Graphic3d_ShaderFlags_MeshEdges|Graphic3d_ShaderFlags_PointCircle, }; #endif // _Graphic3d_ShaderFlags_HeaderFile diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index 8650a554df..b031493e18 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "../Shaders/Shaders_LightShadow_glsl.pxx" @@ -51,6 +52,9 @@ namespace return aMaxLimit; } + //! Number of points used for rendering points rendered as physical circles + const Standard_Integer THE_NB_POINT_CIRCLE_SEGMENTS = 5; + #define EOL "\n" //! Compute TexCoord value in Vertex Shader @@ -215,6 +219,10 @@ EOL"}"; const char THE_VERT_gl_Position[] = EOL" gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"; +//! Compute gl_Position as world position for later processing in a geometry shader +const char THE_VERT_gl_ViewPosition[] = +EOL" gl_Position = 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[] = @@ -830,11 +838,44 @@ TCollection_AsciiString Graphic3d_ShaderManager::pointSpriteShadingSrc (const TC return aSrcFragGetColor; } +static TCollection_AsciiString genGeomPassthroughCode(Graphic3d_ShaderObject::ShaderVariableList &theStageInOuts, Standard_Integer theInVertIdx) +{ + TCollection_AsciiString passthrough = TCollection_AsciiString(); + const TCollection_AsciiString aVertIndex (theInVertIdx); + + // pass variables from Vertex shader to Fragment shader through Geometry shader + for (Graphic3d_ShaderObject::ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next()) + { + if (aVarListIter.Value().Stages == (Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT)) + { + const TCollection_AsciiString aVarName = aVarListIter.Value().Name.Token (" ", 2); + if (aVarName.Value (aVarName.Length()) == ']') + { + // copy the whole array + const TCollection_AsciiString aVarName2 = aVarName.Token ("[", 1); + passthrough += TCollection_AsciiString() + + EOL" geomOut." + aVarName2 + " = geomIn[" + aVertIndex + "]." + aVarName2 + ";"; + } + else + { + passthrough += TCollection_AsciiString() + + EOL" geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";"; + } + } + } + + return passthrough; +} + //! Prepare GLSL source for geometry shader according to parameters. -static TCollection_AsciiString prepareGeomMainSrc (Graphic3d_ShaderObject::ShaderVariableList& theUnifoms, - Graphic3d_ShaderObject::ShaderVariableList& theStageInOuts, - Standard_Integer theBits) +static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::ShaderVariableList &theUnifoms, + Graphic3d_ShaderObject::ShaderVariableList &theStageInOuts, + Standard_Integer theBits, int &theNbInputPoints, int &theNbOutputPoints, + Graphic3d_TypeOfPrimitiveArray &theInputArrayType) { + theNbInputPoints = 0; + theNbOutputPoints = 0; + if ((theBits & Graphic3d_ShaderFlags_NeedsGeomShader) == 0) { return TCollection_AsciiString(); @@ -871,48 +912,62 @@ static TCollection_AsciiString prepareGeomMainSrc (Graphic3d_ShaderObject::Shade EOL" vec3 aHeightABC = vec3 (aQuadArea) / aLenABC;" EOL" aHeightABC = max (aHeightABC, vec3 (10.0 * occLineWidth));" // avoid shrunk presentation disappearing at distance EOL" float aQuadModeHeightC = occIsQuadMode ? occLineWidth + 1.0 : 0.0;"; - } - for (Standard_Integer aVertIter = 0; aVertIter < 3; ++aVertIter) - { - const TCollection_AsciiString aVertIndex (aVertIter); - // pass variables from Vertex shader to Fragment shader through Geometry shader - for (Graphic3d_ShaderObject::ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next()) + for (Standard_Integer aVertIter = 0; aVertIter < 3; ++aVertIter) { - if (aVarListIter.Value().Stages == (Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT)) - { - const TCollection_AsciiString aVarName = aVarListIter.Value().Name.Token (" ", 2); - if (aVarName.Value (aVarName.Length()) == ']') - { - // copy the whole array - const TCollection_AsciiString aVarName2 = aVarName.Token ("[", 1); - aSrcMainGeom += TCollection_AsciiString() - + EOL" geomOut." + aVarName2 + " = geomIn[" + aVertIndex + "]." + aVarName2 + ";"; - } - else - { - aSrcMainGeom += TCollection_AsciiString() - + EOL" geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";"; - } - } - } + const TCollection_AsciiString aVertIndex (aVertIter); + aSrcMainGeom += genGeomPassthroughCode(theStageInOuts, aVertIter); - if ((theBits & Graphic3d_ShaderFlags_MeshEdges) != 0) - { switch (aVertIter) { case 0: aSrcMainGeom += EOL" EdgeDistance = vec3 (aHeightABC[0], 0.0, aQuadModeHeightC);"; break; case 1: aSrcMainGeom += EOL" EdgeDistance = vec3 (0.0, aHeightABC[1], aQuadModeHeightC);"; break; case 2: aSrcMainGeom += EOL" EdgeDistance = vec3 (0.0, 0.0, aHeightABC[2]);"; break; } + + aSrcMainGeom += TCollection_AsciiString() + + EOL" gl_Position = gl_in[" + aVertIndex + "].gl_Position;" + EOL" EmitVertex();"; } + + aSrcMainGeom += + EOL " EndPrimitive();"; + + theInputArrayType = Graphic3d_TOPA_TRIANGLES; + + theNbOutputPoints = 3; + theNbInputPoints = 3; + } + + if ((theBits & Graphic3d_ShaderFlags_PointCircle) != 0) + { aSrcMainGeom += TCollection_AsciiString() - + EOL" gl_Position = gl_in[" + aVertIndex + "].gl_Position;" - EOL" EmitVertex();"; + + EOL" vec4 center = gl_in[0].gl_Position;" + + EOL" float pSize = occPointSize / 2.0;" + + genGeomPassthroughCode(theStageInOuts, 0) + + EOL"" + + EOL" int nbSegments = " + THE_NB_POINT_CIRCLE_SEGMENTS + ";" + + EOL"" + + EOL" for (int i = 0; i < nbSegments; ++i) {" + + EOL" float phi = -PI_DIV_2 + (i / float(nbSegments - 1)) * PI;" + + EOL"" + + EOL" float x = pSize * sin(phi);" + + EOL" float y = pSize * cos(phi);" + + EOL"" + + EOL" gl_Position = occProjectionMatrix * (center + vec4(x, y, 0.0, 0.0));" + + EOL" EmitVertex();" + + EOL" gl_Position = occProjectionMatrix * (center + vec4(x, -y, 0.0, 0.0));" + + EOL" EmitVertex();" + + EOL" }" + + EOL"" + + EOL" EndPrimitive();"; + + theNbOutputPoints = THE_NB_POINT_CIRCLE_SEGMENTS * 2; + theInputArrayType = Graphic3d_TOPA_POINTS; + theNbInputPoints = 1; } - aSrcMainGeom += - EOL" EndPrimitive();" - EOL"}"; + + aSrcMainGeom += EOL"}"; return aSrcMainGeom; } @@ -1109,16 +1164,25 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramUnlit (Sta } } + aSrcVertExtraMain += ((theBits & Graphic3d_ShaderFlags_PointCircle) != 0) + ? THE_VERT_gl_ViewPosition + : THE_VERT_gl_Position; + aSrcVert = aSrcVertExtraFunc + EOL"void main()" EOL"{" + aSrcVertExtraMain - + THE_VERT_gl_Position + aSrcVertEndMain + EOL"}"; - TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits); + Standard_Integer aNbGeomInputVerts = 0; + Standard_Integer aNbGeomOutputVerts = 0; + + Graphic3d_TypeOfPrimitiveArray aGeomInputType; + + TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits, aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType); + aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0 ? THE_FRAG_WIREFRAME_COLOR : EOL"#define getFinalColor getColor"; @@ -1139,10 +1203,9 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramUnlit (Sta aProgramSrc->SetNbShadowMaps (0); aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes); aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0); - const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0; - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts)); - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts)); - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); return aProgramSrc; } @@ -1476,6 +1539,11 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramGouraud (c Standard_Integer aNbLights = 0; const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, theLights, !aSrcVertColor.IsEmpty(), false, toUseTexColor, 0); + + aSrcVertExtraMain += ((theBits & Graphic3d_ShaderFlags_PointCircle) != 0) + ? THE_VERT_gl_ViewPosition + : THE_VERT_gl_Position; + aSrcVert = TCollection_AsciiString() + THE_FUNC_transformNormal_world + EOL @@ -1498,10 +1566,13 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramGouraud (c EOL" FrontColor = computeLighting (aNormal, aView, aPositionWorld, true);" EOL" BackColor = computeLighting (aNormal, aView, aPositionWorld, false);" + aSrcVertExtraMain - + THE_VERT_gl_Position + EOL"}"; - TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits); + Standard_Integer aNbGeomInputVerts = 0; + Standard_Integer aNbGeomOutputVerts = 0; + Graphic3d_TypeOfPrimitiveArray aGeomInputType; + + TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits, aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType); aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0 ? THE_FRAG_WIREFRAME_COLOR : EOL"#define getFinalColor getColor"; @@ -1522,10 +1593,9 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramGouraud (c aProgramSrc->SetNbShadowMaps (0); aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes); aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0); - const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0; - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts)); - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts)); - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); return aProgramSrc; } @@ -1704,6 +1774,10 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramPhong (con EOL" }"; } + aSrcVertExtraMain += ((theBits & Graphic3d_ShaderFlags_PointCircle) != 0) + ? THE_VERT_gl_ViewPosition + : THE_VERT_gl_Position; + aSrcVert = TCollection_AsciiString() + aSrcVertExtraFunc + EOL"void main()" @@ -1719,10 +1793,13 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramPhong (con EOL" View = normalize (anEye - PositionWorld.xyz);" EOL" }" + aSrcVertExtraMain - + THE_VERT_gl_Position + EOL"}"; - TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits); + Standard_Integer aNbGeomInputVerts = 0; + Standard_Integer aNbGeomOutputVerts = 0; + Graphic3d_TypeOfPrimitiveArray aGeomInputType; + + TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits, aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType); aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0 ? THE_FRAG_WIREFRAME_COLOR : EOL"#define getFinalColor getColor"; @@ -1753,10 +1830,10 @@ Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramPhong (con aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes); aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0); - const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0; - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts)); - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts)); - aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts, aNbGeomOutputVerts, aGeomInputType)); + return aProgramSrc; } diff --git a/src/Graphic3d/Graphic3d_ShaderObject.cxx b/src/Graphic3d/Graphic3d_ShaderObject.cxx index 10d109fbe8..b9ecb33c56 100755 --- a/src/Graphic3d/Graphic3d_ShaderObject.cxx +++ b/src/Graphic3d/Graphic3d_ShaderObject.cxx @@ -101,7 +101,9 @@ Handle(Graphic3d_ShaderObject) Graphic3d_ShaderObject::CreateFromSource (TCollec const ShaderVariableList& theStageInOuts, const TCollection_AsciiString& theInName, const TCollection_AsciiString& theOutName, - Standard_Integer theNbGeomInputVerts) + Standard_Integer theNbGeomInputVerts, + Standard_Integer theNbGeomOutputVerts, + Graphic3d_TypeOfPrimitiveArray theGeometryInputType) { if (theSource.IsEmpty()) { @@ -135,7 +137,7 @@ Handle(Graphic3d_ShaderObject) Graphic3d_ShaderObject::CreateFromSource (TCollec continue; } - const Standard_Boolean hasGeomStage = theNbGeomInputVerts > 0 + const Standard_Boolean hasGeomStage = theNbGeomOutputVerts > 0 && aStageLower < Graphic3d_TOS_GEOMETRY && aStageUpper >= Graphic3d_TOS_GEOMETRY; const Standard_Boolean isAllStagesVar = aStageLower == Graphic3d_TOS_VERTEX @@ -192,9 +194,21 @@ Handle(Graphic3d_ShaderObject) Graphic3d_ShaderObject::CreateFromSource (TCollec if (theType == Graphic3d_TOS_GEOMETRY) { + TCollection_AsciiString aGeomShaderInput; + + switch (theGeometryInputType) { + case Graphic3d_TOPA_POINTS: + aGeomShaderInput = "points"; + break; + case Graphic3d_TOPA_TRIANGLES: + default: + aGeomShaderInput = "triangles"; + break; + } + aSrcUniforms.Prepend (TCollection_AsciiString() - + "\nlayout (triangles) in;" - "\nlayout (triangle_strip, max_vertices = " + theNbGeomInputVerts + ") out;"); + + "\nlayout (" + aGeomShaderInput + ") in;" + "\nlayout (triangle_strip, max_vertices = " + theNbGeomOutputVerts + ") out;"); } if (!aSrcInStructs.IsEmpty() && theType == Graphic3d_TOS_GEOMETRY) @@ -223,5 +237,10 @@ Handle(Graphic3d_ShaderObject) Graphic3d_ShaderObject::CreateFromSource (TCollec } theSource.Prepend (aSrcUniforms + aSrcInStructs + aSrcOutStructs + aSrcInOuts); + + if (theType == Graphic3d_TOS_GEOMETRY) { + std::cout << theSource << std::endl; + } + return Graphic3d_ShaderObject::CreateFromSource (theType, theSource); } diff --git a/src/Graphic3d/Graphic3d_ShaderObject.hxx b/src/Graphic3d/Graphic3d_ShaderObject.hxx index 6218bfb74c..531507ff08 100755 --- a/src/Graphic3d/Graphic3d_ShaderObject.hxx +++ b/src/Graphic3d/Graphic3d_ShaderObject.hxx @@ -17,6 +17,7 @@ #define _Graphic3d_ShaderObject_HeaderFile #include +#include #include #include @@ -72,7 +73,9 @@ public: const ShaderVariableList& theStageInOuts, const TCollection_AsciiString& theInName = TCollection_AsciiString(), const TCollection_AsciiString& theOutName = TCollection_AsciiString(), - Standard_Integer theNbGeomInputVerts = 0); + Standard_Integer theNbGeomInputVerts = 0, + Standard_Integer theNbGeomOutputVerts = 0, + Graphic3d_TypeOfPrimitiveArray theGeometryInputType = Graphic3d_TOPA_TRIANGLES); private: diff --git a/src/OpenGl/OpenGl_AspectsSprite.cxx b/src/OpenGl/OpenGl_AspectsSprite.cxx index fe9309b44f..546fa10959 100644 --- a/src/OpenGl/OpenGl_AspectsSprite.cxx +++ b/src/OpenGl/OpenGl_AspectsSprite.cxx @@ -101,7 +101,7 @@ void OpenGl_AspectsSprite::UpdateRediness (const Handle(Graphic3d_Aspects)& theA { // update sprite resource bindings TCollection_AsciiString aSpriteKeyNew, aSpriteAKeyNew; - spriteKeys (theAspect->MarkerImage(), theAspect->MarkerType(), theAspect->MarkerScale(), theAspect->ColorRGBA(), aSpriteKeyNew, aSpriteAKeyNew); + spriteKeys (theAspect->MarkerImage(), theAspect->MarkerType(), theAspect->MarkerScale(), theAspect->MarkerPhysical(), theAspect->ColorRGBA(), aSpriteKeyNew, aSpriteAKeyNew); const TCollection_AsciiString& aSpriteKeyOld = !mySprite.IsNull() ? mySprite ->ResourceId() : THE_EMPTY_KEY; const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY; if (aSpriteKeyNew.IsEmpty() || aSpriteKeyOld != aSpriteKeyNew @@ -122,7 +122,7 @@ const Handle(OpenGl_PointSprite)& OpenGl_AspectsSprite::Sprite (const Handle(Ope { if (!myIsSpriteReady) { - build (theCtx, theAspects->MarkerImage(), theAspects->MarkerType(), theAspects->MarkerScale(), theAspects->ColorRGBA(), myMarkerSize); + build (theCtx, theAspects->MarkerImage(), theAspects->MarkerType(), theAspects->MarkerScale(), theAspects->MarkerPhysical(), theAspects->ColorRGBA(), myMarkerSize); myIsSpriteReady = true; } return theIsAlphaSprite && !mySpriteA.IsNull() && mySpriteA->IsValid() @@ -138,12 +138,13 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx, const Handle(Graphic3d_MarkerImage)& theMarkerImage, Aspect_TypeOfMarker theType, Standard_ShortReal theScale, + Standard_Boolean thePhysicalScale, const Graphic3d_Vec4& theColor, Standard_ShortReal& theMarkerSize) { // generate key for shared resource TCollection_AsciiString aNewKey, aNewKeyA; - spriteKeys (theMarkerImage, theType, theScale, theColor, aNewKey, aNewKeyA); + spriteKeys (theMarkerImage, theType, theScale, thePhysicalScale, theColor, aNewKey, aNewKeyA); const TCollection_AsciiString& aSpriteKeyOld = !mySprite.IsNull() ? mySprite ->ResourceId() : THE_EMPTY_KEY; const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY; @@ -336,6 +337,7 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx, void OpenGl_AspectsSprite::spriteKeys (const Handle(Graphic3d_MarkerImage)& theMarkerImage, Aspect_TypeOfMarker theType, Standard_ShortReal theScale, + Standard_Boolean thePhysicalScale, const Graphic3d_Vec4& theColor, TCollection_AsciiString& theKey, TCollection_AsciiString& theKeyA) @@ -350,7 +352,8 @@ void OpenGl_AspectsSprite::spriteKeys (const Handle(Graphic3d_MarkerImage)& theM } } else if (theType != Aspect_TOM_POINT - && theType != Aspect_TOM_EMPTY) + && theType != Aspect_TOM_EMPTY + && !thePhysicalScale) { // predefined markers are defined with 0.5 step const Standard_Integer aScale = Standard_Integer(theScale * 10.0f + 0.5f); diff --git a/src/OpenGl/OpenGl_AspectsSprite.hxx b/src/OpenGl/OpenGl_AspectsSprite.hxx index e7f1a0002e..f1ef3aa29a 100644 --- a/src/OpenGl/OpenGl_AspectsSprite.hxx +++ b/src/OpenGl/OpenGl_AspectsSprite.hxx @@ -31,6 +31,8 @@ public: Standard_ShortReal MarkerSize() const { return myMarkerSize; } + Standard_Boolean MarkerPhysical() const { return myMarkerPhysical; } + //! Return TRUE if resource is up-to-date. bool IsReady() const { return myIsSpriteReady; } @@ -63,6 +65,7 @@ private: const Handle(Graphic3d_MarkerImage)& theMarkerImage, Aspect_TypeOfMarker theType, Standard_ShortReal theScale, + Standard_Boolean thePhysicalScale, const Graphic3d_Vec4& theColor, Standard_ShortReal& theMarkerSize); @@ -70,6 +73,7 @@ private: static void spriteKeys (const Handle(Graphic3d_MarkerImage)& theMarkerImage, Aspect_TypeOfMarker theType, Standard_ShortReal theScale, + Standard_Boolean thePhysicalScale, const Graphic3d_Vec4& theColor, TCollection_AsciiString& theKey, TCollection_AsciiString& theKeyA); @@ -78,8 +82,10 @@ private: Handle(OpenGl_PointSprite) mySprite; Handle(OpenGl_PointSprite) mySpriteA; + Standard_ShortReal myMarkerSize; Standard_Boolean myIsSpriteReady; + Standard_Boolean myMarkerPhysical; }; diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx index 151d1cc40a..80939ae046 100644 --- a/src/OpenGl/OpenGl_PrimitiveArray.cxx +++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx @@ -932,7 +932,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace { aShadingModel = aCtx->ShaderManager()->ChooseMarkerShadingModel (anAspectFace->ShadingModel(), hasVertNorm); aCtx->ShaderManager()->BindMarkerProgram (aTextureSet, - aShadingModel, Graphic3d_AlphaMode_Opaque, + aShadingModel, Graphic3d_AlphaMode_Opaque, anAspectFace->Aspect()->MarkerPhysical(), hasVertColor, anAspectFace->ShaderProgramRes (aCtx)); break; } diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index eff6bf9f39..ca8cd52a84 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -1424,6 +1424,7 @@ Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl Standard_Boolean OpenGl_ShaderManager::BindMarkerProgram (const Handle(OpenGl_TextureSet)& theTextures, Graphic3d_TypeOfShadingModel theShadingModel, Graphic3d_AlphaMode theAlphaMode, + Standard_Boolean theRenderPhysicalCircle, Standard_Boolean theHasVertColor, const Handle(OpenGl_ShaderProgram)& theCustomProgram) { @@ -1443,6 +1444,11 @@ Standard_Boolean OpenGl_ShaderManager::BindMarkerProgram (const Handle(OpenGl_Te { aBits |= Graphic3d_ShaderFlags_PointSimple; } + + if (theRenderPhysicalCircle) { + aBits |= Graphic3d_ShaderFlags_PointCircle; + } + Handle(OpenGl_ShaderProgram)& aProgram = getStdProgram (theShadingModel, aBits); return bindProgramWithState (aProgram, theShadingModel); } diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index f8dc9da70b..5282d84254 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -157,6 +157,7 @@ public: Standard_EXPORT Standard_Boolean BindMarkerProgram (const Handle(OpenGl_TextureSet)& theTextures, Graphic3d_TypeOfShadingModel theShadingModel, Graphic3d_AlphaMode theAlphaMode, + Standard_Boolean theRenderPhysicalCircle, Standard_Boolean theHasVertColor, const Handle(OpenGl_ShaderProgram)& theCustomProgram); From a47f9daa2e26a55b0df66f2786f23036f3220a43 Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Tue, 29 Oct 2024 13:39:42 +1100 Subject: [PATCH 2/9] Remove debug out --- src/Graphic3d/Graphic3d_ShaderObject.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Graphic3d/Graphic3d_ShaderObject.cxx b/src/Graphic3d/Graphic3d_ShaderObject.cxx index b9ecb33c56..84a73ee2c5 100755 --- a/src/Graphic3d/Graphic3d_ShaderObject.cxx +++ b/src/Graphic3d/Graphic3d_ShaderObject.cxx @@ -238,9 +238,5 @@ Handle(Graphic3d_ShaderObject) Graphic3d_ShaderObject::CreateFromSource (TCollec theSource.Prepend (aSrcUniforms + aSrcInStructs + aSrcOutStructs + aSrcInOuts); - if (theType == Graphic3d_TOS_GEOMETRY) { - std::cout << theSource << std::endl; - } - return Graphic3d_ShaderObject::CreateFromSource (theType, theSource); } From 9c26429cdd2b783ad8a5aad83b27ff154f76a45b Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Tue, 29 Oct 2024 13:42:42 +1100 Subject: [PATCH 3/9] Reduce per-circle triangles by two --- src/Graphic3d/Graphic3d_ShaderManager.cxx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index b031493e18..4798259416 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -53,7 +53,7 @@ namespace } //! Number of points used for rendering points rendered as physical circles - const Standard_Integer THE_NB_POINT_CIRCLE_SEGMENTS = 5; + const Standard_Integer THE_NB_POINT_CIRCLE_SEGMENTS = 7; #define EOL "\n" @@ -943,26 +943,30 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader { aSrcMainGeom += TCollection_AsciiString() + EOL" vec4 center = gl_in[0].gl_Position;" - + EOL" float pSize = occPointSize / 2.0;" + + EOL" float pRadius = occPointSize / 2.0;" + genGeomPassthroughCode(theStageInOuts, 0) + EOL"" - + EOL" int nbSegments = " + THE_NB_POINT_CIRCLE_SEGMENTS + ";" + + EOL" const int nbSegments = " + THE_NB_POINT_CIRCLE_SEGMENTS + ";" + EOL"" - + EOL" for (int i = 0; i < nbSegments; ++i) {" + + EOL" gl_Position = occProjectionMatrix * (center + vec4(pRadius, 0.0, 0.0, 0.0));" + + EOL" EmitVertex();" + + EOL" for (int i = (nbSegments - 2); i >= 1; --i) {" + EOL" float phi = -PI_DIV_2 + (i / float(nbSegments - 1)) * PI;" + EOL"" - + EOL" float x = pSize * sin(phi);" - + EOL" float y = pSize * cos(phi);" + + EOL" float x = pRadius * sin(phi);" + + EOL" float y = pRadius * cos(phi);" + EOL"" + EOL" gl_Position = occProjectionMatrix * (center + vec4(x, y, 0.0, 0.0));" + EOL" EmitVertex();" + EOL" gl_Position = occProjectionMatrix * (center + vec4(x, -y, 0.0, 0.0));" + EOL" EmitVertex();" + EOL" }" + + EOL" gl_Position = occProjectionMatrix * (center + vec4(-pRadius, 0.0, 0.0, 0.0));" + + EOL" EmitVertex();" + EOL"" + EOL" EndPrimitive();"; - theNbOutputPoints = THE_NB_POINT_CIRCLE_SEGMENTS * 2; + theNbOutputPoints = THE_NB_POINT_CIRCLE_SEGMENTS * 2 - 2; theInputArrayType = Graphic3d_TOPA_POINTS; theNbInputPoints = 1; } From 33917962c5d213bbe0262eb00b2a038dbe81e6f9 Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Wed, 30 Oct 2024 14:58:24 +1100 Subject: [PATCH 4/9] Render lines using a geometry shader to allow OpenGL core line width rendering --- src/Graphic3d/Graphic3d_ShaderFlags.hxx | 5 ++- src/Graphic3d/Graphic3d_ShaderManager.cxx | 45 +++++++++++++++++++++++ src/Graphic3d/Graphic3d_ShaderObject.cxx | 8 ++++ src/OpenGl/OpenGl_PrimitiveArray.cxx | 20 +++++++++- src/OpenGl/OpenGl_ShaderManager.hxx | 7 ++++ src/OpenGl/OpenGl_Structure.cxx | 2 +- src/OpenGlTest/OpenGlTest_Commands.cxx | 2 +- 7 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/Graphic3d/Graphic3d_ShaderFlags.hxx b/src/Graphic3d/Graphic3d_ShaderFlags.hxx index 0b3b7f379c..4fa1435897 100644 --- a/src/Graphic3d/Graphic3d_ShaderFlags.hxx +++ b/src/Graphic3d/Graphic3d_ShaderFlags.hxx @@ -36,12 +36,13 @@ enum Graphic3d_ShaderFlags Graphic3d_ShaderFlags_WriteOit = 0x0800, //!< write coverage buffer for Blended Order-Independent Transparency Graphic3d_ShaderFlags_OitDepthPeeling = 0x1000, //!< handle Depth Peeling OIT Graphic3d_ShaderFlags_PointCircle = 0x2000, //!< output points as circle billboards with diameter (gl_PointSize) instead + Graphic3d_ShaderFlags_LineWidth = 0x4000, //!< expand line primitives in screen space using triangles // - Graphic3d_ShaderFlags_NB = 0x4000, //!< overall number of combinations + Graphic3d_ShaderFlags_NB = 0x8000, //!< overall number of combinations Graphic3d_ShaderFlags_IsPoint = Graphic3d_ShaderFlags_PointSimple|Graphic3d_ShaderFlags_PointSprite| Graphic3d_ShaderFlags_PointSpriteA|Graphic3d_ShaderFlags_PointCircle, Graphic3d_ShaderFlags_HasTextures = Graphic3d_ShaderFlags_TextureRGB|Graphic3d_ShaderFlags_TextureEnv, - Graphic3d_ShaderFlags_NeedsGeomShader = Graphic3d_ShaderFlags_MeshEdges|Graphic3d_ShaderFlags_PointCircle, + Graphic3d_ShaderFlags_NeedsGeomShader = Graphic3d_ShaderFlags_MeshEdges|Graphic3d_ShaderFlags_PointCircle|Graphic3d_ShaderFlags_LineWidth, }; #endif // _Graphic3d_ShaderFlags_HeaderFile diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index 4798259416..d0c520bb21 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -971,6 +971,51 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader theNbInputPoints = 1; } + if ((theBits & Graphic3d_ShaderFlags_LineWidth) != 0) + { + theUnifoms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 occViewport", Graphic3d_TOS_GEOMETRY)); + theUnifoms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occLineWidth", Graphic3d_TOS_GEOMETRY)); + + aSrcMainGeom = TCollection_AsciiString() + + EOL"vec3 ToViewPortTransform (vec4 theVec)" + EOL"{" + EOL" vec3 aWinCoord = theVec.xyz / theVec.w;" + EOL" aWinCoord = aWinCoord * 0.5 + 0.5;" + EOL" aWinCoord.xy = aWinCoord.xy * occViewport.zw + occViewport.xy;" + EOL" return aWinCoord;" + EOL"}" + + EOL"vec4 FromViewPortTransform (vec3 theVec)" + EOL"{" + EOL" vec3 aNdcCoord = vec3(theVec.xy / (occViewport.zw + occViewport.xy), theVec.z);" + EOL" aNdcCoord = aNdcCoord * 2.0 - 1.0;" + EOL" return vec4(aNdcCoord, 1.0);" + EOL"}" + + aSrcMainGeom + + EOL" vec3 aLineA = ToViewPortTransform(gl_in[0].gl_Position);" + + EOL" vec3 aLineB = ToViewPortTransform(gl_in[1].gl_Position);" + + EOL"" + + EOL" vec3 aLineDir = normalize(aLineB - aLineA);" + + EOL" vec3 aLinePerpPosDir = vec3(-aLineDir.y, aLineDir.x, 0.0);" + + EOL"" + + EOL" float aLineSideWidth = occLineWidth / 2.0;" + + genGeomPassthroughCode(theStageInOuts, 0) + + EOL" gl_Position = FromViewPortTransform(aLineA + aLineSideWidth * aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL" gl_Position = FromViewPortTransform(aLineA + aLineSideWidth * -aLinePerpPosDir);" + + EOL" EmitVertex();" + + genGeomPassthroughCode(theStageInOuts, 1) + + EOL" gl_Position = FromViewPortTransform(aLineB + aLineSideWidth * aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL" gl_Position = FromViewPortTransform(aLineB + aLineSideWidth * -aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL"" + + EOL" EndPrimitive();"; + + theNbOutputPoints = 4; + theInputArrayType = Graphic3d_TOPA_POLYLINES; + theNbInputPoints = 2; + } + aSrcMainGeom += EOL"}"; return aSrcMainGeom; diff --git a/src/Graphic3d/Graphic3d_ShaderObject.cxx b/src/Graphic3d/Graphic3d_ShaderObject.cxx index 84a73ee2c5..fbdab2233d 100755 --- a/src/Graphic3d/Graphic3d_ShaderObject.cxx +++ b/src/Graphic3d/Graphic3d_ShaderObject.cxx @@ -197,6 +197,14 @@ Handle(Graphic3d_ShaderObject) Graphic3d_ShaderObject::CreateFromSource (TCollec TCollection_AsciiString aGeomShaderInput; switch (theGeometryInputType) { + case Graphic3d_TOPA_POLYLINES: + case Graphic3d_TOPA_SEGMENTS: + aGeomShaderInput = "lines"; + break; + case Graphic3d_TOPA_LINE_STRIP_ADJACENCY: + case Graphic3d_TOPA_LINES_ADJACENCY: + aGeomShaderInput = "lines_adjacency"; + break; case Graphic3d_TOPA_POINTS: aGeomShaderInput = "points"; break; diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx index 80939ae046..ceef983905 100644 --- a/src/OpenGl/OpenGl_PrimitiveArray.cxx +++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx @@ -501,7 +501,7 @@ void OpenGl_PrimitiveArray::drawEdges (const Handle(OpenGl_Workspace)& theWorksp if (aGlContext->core20fwd != NULL) { aGlContext->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), anAspect->Aspect()->EdgeLineType(), - Graphic3d_TypeOfShadingModel_Unlit, Graphic3d_AlphaMode_Opaque, Standard_False, + Graphic3d_TypeOfShadingModel_Unlit, Graphic3d_AlphaMode_Opaque, Standard_False, Standard_False, anAspect->ShaderProgramRes (aGlContext)); } aGlContext->SetSampleAlphaToCoverage (aGlContext->ShaderManager()->MaterialState().HasAlphaCutoff()); @@ -847,7 +847,18 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext(); bool toDrawArray = true, toSetLinePolygMode = false; + int toDrawInteriorEdges = 0; // 0 - no edges, 1 - glsl edges, 2 - polygonMode + int toDrawLineGeometry = 1; // 1 - render using FFP, 2 - render using glsl + + if (myDrawMode == GL_LINES || myDrawMode == GL_LINE_STRIP) + { + if (aCtx->hasGeometryStage != OpenGl_FeatureNotAvailable) + { + toDrawLineGeometry = 2; + } + } + if (myIsFillType) { toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY; @@ -945,7 +956,14 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace aShadingModel, Graphic3d_AlphaMode_Opaque, hasVertColor, + toDrawLineGeometry == 2, anAspectFace->ShaderProgramRes (aCtx)); + + if (toDrawLineGeometry == 2) + { + aCtx->ShaderManager()->PushInteriorState (aCtx->ActiveProgram(), anAspectFace->Aspect()); + } + break; } default: diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index 5282d84254..cefc4feb07 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -135,6 +135,7 @@ public: const Graphic3d_TypeOfShadingModel theShadingModel, const Graphic3d_AlphaMode theAlphaMode, const Standard_Boolean theHasVertColor, + const Standard_Boolean theEnableLineGeometry, const Handle(OpenGl_ShaderProgram)& theCustomProgram) { if (!theCustomProgram.IsNull() @@ -144,6 +145,12 @@ public: } Standard_Integer aBits = getProgramBits (theTextures, theAlphaMode, Aspect_IS_SOLID, theHasVertColor, false, false); + + if (theEnableLineGeometry) + { + aBits |= Graphic3d_ShaderFlags_LineWidth; + } + if (theLineType != Aspect_TOL_SOLID) { aBits |= Graphic3d_ShaderFlags_StippleLine; diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx index d5c3c5270b..f576ce3b5d 100644 --- a/src/OpenGl/OpenGl_Structure.cxx +++ b/src/OpenGl/OpenGl_Structure.cxx @@ -83,7 +83,7 @@ void OpenGl_Structure::renderBoundingBox (const Handle(OpenGl_Workspace)& theWor OpenGl_Vec3 (aMin.x(), aMin.y(), aMax.z()) }; - aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID, Graphic3d_TypeOfShadingModel_Unlit, Graphic3d_AlphaMode_Opaque, false, Handle(OpenGl_ShaderProgram)()); + aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID, Graphic3d_TypeOfShadingModel_Unlit, Graphic3d_AlphaMode_Opaque, false, false, Handle(OpenGl_ShaderProgram)()); aCtx->SetColor4fv (theWorkspace->InteriorColor()); aCtx->core11fwd->glDisable (GL_LIGHTING); aCtx->core11ffp->glEnableClientState (GL_VERTEX_ARRAY); diff --git a/src/OpenGlTest/OpenGlTest_Commands.cxx b/src/OpenGlTest/OpenGlTest_Commands.cxx index 77203b21ab..cddcc94272 100644 --- a/src/OpenGlTest/OpenGlTest_Commands.cxx +++ b/src/OpenGlTest/OpenGlTest_Commands.cxx @@ -165,7 +165,7 @@ void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const OpenGl_Vec4 aColor = theWorkspace->InteriorColor(); aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID, - Graphic3d_TypeOfShadingModel_Unlit, Graphic3d_AlphaMode_Opaque, false, + Graphic3d_TypeOfShadingModel_Unlit, Graphic3d_AlphaMode_Opaque, false, false, Handle(OpenGl_ShaderProgram)()); aCtx->SetColor4fv (aColor); From 7e083f600cdc46903898891beeb205061da7846d Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Wed, 30 Oct 2024 15:37:54 +1100 Subject: [PATCH 5/9] Add circular end caps to rendered lines --- src/Graphic3d/Graphic3d_ShaderManager.cxx | 39 +++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index d0c520bb21..63701889ca 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -55,6 +55,9 @@ namespace //! Number of points used for rendering points rendered as physical circles const Standard_Integer THE_NB_POINT_CIRCLE_SEGMENTS = 7; + //! Number of points used for rendering circular end caps of lines + const Standard_Integer THE_LINE_END_CAP_SEGMENTS = 4; + #define EOL "\n" //! Compute TexCoord value in Vertex Shader @@ -994,11 +997,29 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader + EOL" vec3 aLineA = ToViewPortTransform(gl_in[0].gl_Position);" + EOL" vec3 aLineB = ToViewPortTransform(gl_in[1].gl_Position);" + EOL"" + + EOL" aLineA.z -= 0.0001;" + + EOL" aLineB.z -= 0.0001;" + + EOL"" + EOL" vec3 aLineDir = normalize(aLineB - aLineA);" + EOL" vec3 aLinePerpPosDir = vec3(-aLineDir.y, aLineDir.x, 0.0);" + EOL"" - + EOL" float aLineSideWidth = occLineWidth / 2.0;" + + EOL" const int nbSegments = " + THE_LINE_END_CAP_SEGMENTS + ";" + genGeomPassthroughCode(theStageInOuts, 0) + + EOL" float aLineSideWidth = occLineWidth;" + + EOL" gl_Position = FromViewPortTransform(aLineA - aLineDir * aLineSideWidth);" + + EOL" EmitVertex();" + + EOL" for (int i = 1; i < nbSegments - 1; ++i) {" + + EOL" float phi = (i / float(nbSegments - 1)) * PI_DIV_2;" + + EOL"" + + EOL" float x = aLineSideWidth * sin(phi);" + + EOL" float y = aLineSideWidth * cos(phi);" + + EOL"" + + EOL" gl_Position = FromViewPortTransform(aLineA + y * -aLineDir + x * aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL" gl_Position = FromViewPortTransform(aLineA + y * -aLineDir + -x * aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL" }" + + EOL"" + EOL" gl_Position = FromViewPortTransform(aLineA + aLineSideWidth * aLinePerpPosDir);" + EOL" EmitVertex();" + EOL" gl_Position = FromViewPortTransform(aLineA + aLineSideWidth * -aLinePerpPosDir);" @@ -1009,9 +1030,23 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader + EOL" gl_Position = FromViewPortTransform(aLineB + aLineSideWidth * -aLinePerpPosDir);" + EOL" EmitVertex();" + EOL"" + + EOL" for (int i = 1; i < nbSegments - 1; ++i) {" + + EOL" float phi = PI_DIV_2 + (i / float(nbSegments - 1)) * PI_DIV_2;" + + EOL"" + + EOL" float x = aLineSideWidth * sin(phi);" + + EOL" float y = aLineSideWidth * cos(phi);" + + EOL"" + + EOL" gl_Position = FromViewPortTransform(aLineB + y * -aLineDir + x * aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL" gl_Position = FromViewPortTransform(aLineB + y * -aLineDir + -x * aLinePerpPosDir);" + + EOL" EmitVertex();" + + EOL" }" + + EOL" gl_Position = FromViewPortTransform(aLineB + aLineDir * aLineSideWidth);" + + EOL" EmitVertex();" + + EOL"" + EOL" EndPrimitive();"; - theNbOutputPoints = 4; + theNbOutputPoints = 4 + ((Max(THE_LINE_END_CAP_SEGMENTS, 2) - 2) * 2 + 1) * 2; theInputArrayType = Graphic3d_TOPA_POLYLINES; theNbInputPoints = 2; } From 83f5a759178acdd3543793269ba117c477752ac3 Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Wed, 30 Oct 2024 15:56:57 +1100 Subject: [PATCH 6/9] Add OpenGl_Cap to disable line geometry shader --- src/OpenGl/OpenGl_Caps.cxx | 2 ++ src/OpenGl/OpenGl_Caps.hxx | 1 + src/OpenGl/OpenGl_PrimitiveArray.cxx | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/OpenGl/OpenGl_Caps.cxx b/src/OpenGl/OpenGl_Caps.cxx index 140a767d00..220b0b7bb5 100755 --- a/src/OpenGl/OpenGl_Caps.cxx +++ b/src/OpenGl/OpenGl_Caps.cxx @@ -29,6 +29,7 @@ OpenGl_Caps::OpenGl_Caps() keepArrayData (Standard_False), ffpEnable (Standard_False), usePolygonMode (Standard_False), + lineGeomDisable (Standard_False), useSystemBuffer (Standard_False), swapInterval (1), useZeroToOneDepth (Standard_False), @@ -71,6 +72,7 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy) ffpEnable = theCopy.ffpEnable; useSystemBuffer = theCopy.useSystemBuffer; swapInterval = theCopy.swapInterval; + lineGeomDisable = theCopy.lineGeomDisable; useZeroToOneDepth = theCopy.useZeroToOneDepth; buffersNoSwap = theCopy.buffersNoSwap; buffersOpaqueAlpha= theCopy.buffersOpaqueAlpha; diff --git a/src/OpenGl/OpenGl_Caps.hxx b/src/OpenGl/OpenGl_Caps.hxx index 5281e046da..ce66076afc 100755 --- a/src/OpenGl/OpenGl_Caps.hxx +++ b/src/OpenGl/OpenGl_Caps.hxx @@ -34,6 +34,7 @@ public: //! @name flags to disable particular functionality, should be used only Standard_Boolean keepArrayData; //!< Disables freeing CPU memory after building VBOs (OFF by default) Standard_Boolean ffpEnable; //!< Enables FFP (fixed-function pipeline), do not use built-in GLSL programs (OFF by default) Standard_Boolean usePolygonMode; //!< Enables Polygon Mode instead of built-in GLSL programs (OFF by default; unsupported on OpenGL ES) + Standard_Boolean lineGeomDisable; //!< Disables GLSL shader for line rendering (OFF by default) Standard_Boolean useSystemBuffer; //!< Enables usage of system backbuffer for blitting (OFF by default on desktop OpenGL and ON on OpenGL ES for testing) Standard_Integer swapInterval; //!< controls swap interval - 0 for VSync off and 1 for VSync on, 1 by default Standard_Boolean useZeroToOneDepth; //!< use [0, 1] depth range instead of [-1, 1] range, when possible (OFF by default) diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx index ceef983905..fd2e21ae32 100644 --- a/src/OpenGl/OpenGl_PrimitiveArray.cxx +++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx @@ -853,7 +853,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace if (myDrawMode == GL_LINES || myDrawMode == GL_LINE_STRIP) { - if (aCtx->hasGeometryStage != OpenGl_FeatureNotAvailable) + if (aCtx->hasGeometryStage != OpenGl_FeatureNotAvailable && !aCtx->caps->lineGeomDisable) { toDrawLineGeometry = 2; } From ac3cad981bc647c1643063c7b0e440375098e9bf Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Thu, 31 Oct 2024 11:12:33 +1100 Subject: [PATCH 7/9] Remove NDC z-offs --- src/Graphic3d/Graphic3d_ShaderManager.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index 63701889ca..fa9433305d 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -997,9 +997,6 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader + EOL" vec3 aLineA = ToViewPortTransform(gl_in[0].gl_Position);" + EOL" vec3 aLineB = ToViewPortTransform(gl_in[1].gl_Position);" + EOL"" - + EOL" aLineA.z -= 0.0001;" - + EOL" aLineB.z -= 0.0001;" - + EOL"" + EOL" vec3 aLineDir = normalize(aLineB - aLineA);" + EOL" vec3 aLinePerpPosDir = vec3(-aLineDir.y, aLineDir.x, 0.0);" + EOL"" From dba11bcd9235c943712e4de7f28da776542cbc74 Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Thu, 31 Oct 2024 12:16:34 +1100 Subject: [PATCH 8/9] Line side widths should be half --- src/Graphic3d/Graphic3d_ShaderManager.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index fa9433305d..0e3d644fc8 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -1002,7 +1002,7 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader + EOL"" + EOL" const int nbSegments = " + THE_LINE_END_CAP_SEGMENTS + ";" + genGeomPassthroughCode(theStageInOuts, 0) - + EOL" float aLineSideWidth = occLineWidth;" + + EOL" float aLineSideWidth = occLineWidth / 2.0;" + EOL" gl_Position = FromViewPortTransform(aLineA - aLineDir * aLineSideWidth);" + EOL" EmitVertex();" + EOL" for (int i = 1; i < nbSegments - 1; ++i) {" From eef2a27167dabe6792910196be839cfb90a2c058 Mon Sep 17 00:00:00 2001 From: Win Holzapfel Date: Thu, 31 Oct 2024 19:35:37 +1100 Subject: [PATCH 9/9] Only process visible points --- src/Graphic3d/Graphic3d_ShaderManager.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Graphic3d/Graphic3d_ShaderManager.cxx b/src/Graphic3d/Graphic3d_ShaderManager.cxx index 0e3d644fc8..2f047677f2 100644 --- a/src/Graphic3d/Graphic3d_ShaderManager.cxx +++ b/src/Graphic3d/Graphic3d_ShaderManager.cxx @@ -946,6 +946,16 @@ static TCollection_AsciiString prepareGeomMainSrc(Graphic3d_ShaderObject::Shader { aSrcMainGeom += TCollection_AsciiString() + EOL" vec4 center = gl_in[0].gl_Position;" + + EOL" vec4 centerNdc = occProjectionMatrix * center;" + + EOL" vec3 normNdc = centerNdc.xyz / centerNdc.w;" + + EOL"" + + EOL" if (!((normNdc.x >= -1.0 && normNdc.x <= 1.0) &&" + + EOL" (normNdc.y >= -1.0 && normNdc.y <= 1.0) &&" + + EOL" (normNdc.z >= -1.0 && normNdc.z <= 1.0))) {" + + EOL" EndPrimitive();" + + EOL" return;" + + EOL" }" + + EOL"" + EOL" float pRadius = occPointSize / 2.0;" + genGeomPassthroughCode(theStageInOuts, 0) + EOL""