diff --git a/src/AIS/AIS_ColoredShape.cxx b/src/AIS/AIS_ColoredShape.cxx index ec68acf925..516042e75d 100644 --- a/src/AIS/AIS_ColoredShape.cxx +++ b/src/AIS/AIS_ColoredShape.cxx @@ -636,12 +636,22 @@ void AIS_ColoredShape::addShapesWithCustomProps (const Handle(Prs3d_Presentation { if (Handle(Graphic3d_ArrayOfSegments) aBndSegments = StdPrs_ShadedShape::FillFaceBoundaries (aShapeDraw, aDrawer->FaceBoundaryUpperContinuity())) { - if (anEdgesGroup.IsNull()) + Handle(Graphic3d_AspectLine3d) aLineAspect = aDrawer->FaceBoundaryAspect()->Aspect(); + if (aDrawer->FaceBoundaryShadingOverride()) + { + Quantity_Color aColor = aDrawer->Color(); + if (aDrawer->HasOwnShadingAspect()) + { + aColor = aDrawer->ShadingAspect()->Color(); + } + aLineAspect->SetColor (aColor); + anEdgesGroup = thePrs->NewGroup(); + } + else if (anEdgesGroup.IsNull()) { anEdgesGroup = thePrs->NewGroup(); } - - anEdgesGroup->SetPrimitivesAspect (aDrawer->FaceBoundaryAspect()->Aspect()); + anEdgesGroup->SetGroupPrimitivesAspect (aLineAspect); anEdgesGroup->AddPrimitiveArray (aBndSegments); } } diff --git a/src/Graphic3d/Graphic3d_ArrayOfSegments.hxx b/src/Graphic3d/Graphic3d_ArrayOfSegments.hxx index 2059c9587a..7706140119 100644 --- a/src/Graphic3d/Graphic3d_ArrayOfSegments.hxx +++ b/src/Graphic3d/Graphic3d_ArrayOfSegments.hxx @@ -54,11 +54,16 @@ public: //! @param theMaxVertexs defines the maximum allowed vertex number in the array //! @param theMaxEdges defines the maximum allowed edge number in the array //! @param theHasVColors when TRUE, AddVertex(Point,Color) should be used for specifying vertex color + //! @param theHasVNormals when TRUE, AddVertex(Point,Normal) or AddVertex(Point,Normal,Color) should be used to specify vertex normal; + //! vertex normals should be specified coherent to the edge's neighbour triangle face's orientation + //! (defined by order of vertexes within triangle) for proper rendering Graphic3d_ArrayOfSegments (Standard_Integer theMaxVertexs, - Standard_Integer theMaxEdges = 0, - Standard_Boolean theHasVColors = Standard_False) - : Graphic3d_ArrayOfPrimitives (Graphic3d_TOPA_SEGMENTS, theMaxVertexs, 0, theMaxEdges, theHasVColors ? Graphic3d_ArrayFlags_VertexColor : Graphic3d_ArrayFlags_None) {} - + Standard_Integer theMaxEdges = 0, + Standard_Boolean theHasVColors = Standard_False, + Standard_Boolean theHasVNormals = Standard_False) + : Graphic3d_ArrayOfPrimitives (Graphic3d_TOPA_SEGMENTS, theMaxVertexs, 0, theMaxEdges, + (theHasVNormals ? Graphic3d_ArrayFlags_VertexNormal : Graphic3d_ArrayFlags_None) + | (theHasVColors ? Graphic3d_ArrayFlags_VertexColor : Graphic3d_ArrayFlags_None)) {} }; diff --git a/src/Prs3d/Prs3d_Drawer.hxx b/src/Prs3d/Prs3d_Drawer.hxx index 38c85647b9..83042c96a6 100644 --- a/src/Prs3d/Prs3d_Drawer.hxx +++ b/src/Prs3d/Prs3d_Drawer.hxx @@ -772,6 +772,17 @@ public: myFaceBoundaryDraw = false; } + //! Return flag value for boundary shading edge color override + Standard_Boolean FaceBoundaryShadingOverride() const + { + return myHasOwnFaceBoundaryDraw || myLink.IsNull() + ? myFaceBoundaryShadingOverride + : myLink->FaceBoundaryShadingOverride(); + } + + //! Return flag value for boundary shading edge color override + void SetFaceBoundaryShadingOverride (Standard_Boolean theFlag) { myFaceBoundaryShadingOverride = theFlag; } + //! Returns true if the drawer has its own attribute for face boundaries upper edge continuity class that overrides the one in the link. Standard_Boolean HasOwnFaceBoundaryUpperContinuity() const { return myFaceBoundaryUpperContinuity != -1; } @@ -1008,6 +1019,7 @@ protected: Standard_Integer myFaceBoundaryUpperContinuity; //!< the most edge continuity class (GeomAbs_Shape) to be included to face boundaries presentation, or -1 if undefined Standard_Boolean myFaceBoundaryDraw; Standard_Boolean myHasOwnFaceBoundaryDraw; + Standard_Boolean myFaceBoundaryShadingOverride; Handle(Prs3d_DimensionAspect) myDimensionAspect; Prs3d_DimensionUnits myDimensionModelUnits; diff --git a/src/StdPrs/StdPrs_ShadedShape.cxx b/src/StdPrs/StdPrs_ShadedShape.cxx index fe2f667dba..ba986bda7f 100644 --- a/src/StdPrs/StdPrs_ShadedShape.cxx +++ b/src/StdPrs/StdPrs_ShadedShape.cxx @@ -299,9 +299,7 @@ namespace // for computing boundaries presentation Standard_Integer aNodeNumber = 0; Standard_Integer aNbPolylines = 0; - - TopLoc_Location aTrsf; - + TopLoc_Location aLoc; Handle(NCollection_Shared) aSeqPntsExtra; for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) { @@ -331,7 +329,7 @@ namespace // take one of the shared edges and get edge triangulation const TopoDS_Face& aFace = TopoDS::Face (anEdgeIter.Value().First()); - Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aTrsf); + Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLoc); if (aTriangulation.IsNull()) { continue; @@ -345,7 +343,7 @@ namespace continue; } - Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf); + Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aLoc); if (!anEdgePoly.IsNull() && anEdgePoly->Nodes().Length() >= 2) { @@ -371,7 +369,9 @@ namespace // create indexed segments array to pack polylines from different edges into single array const Standard_Integer aSegmentEdgeNb = (aNodeNumber - aNbPolylines) * 2; - Handle(Graphic3d_ArrayOfSegments) aSegments = new Graphic3d_ArrayOfSegments (aNodeNumber + aNbExtra, aSegmentEdgeNb + aNbExtra); + const Standard_Boolean aToAddNormals = Standard_True; + Handle(Graphic3d_ArrayOfSegments) aSegments = new Graphic3d_ArrayOfSegments (aNodeNumber + aNbExtra, aSegmentEdgeNb + aNbExtra, + Standard_False, aToAddNormals); for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator anEdgeIter (anEdgesMap); anEdgeIter.More(); anEdgeIter.Next()) { if (anEdgeIter.Value().Extent() == 0) @@ -379,49 +379,75 @@ namespace continue; } - const TopoDS_Face& aFace = TopoDS::Face (anEdgeIter.Value().First()); - Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aTrsf); - if (aTriangulation.IsNull()) + Standard_Integer aFaceIndex = 0; + const Standard_Integer aFirstNodeInFace = aSegments->VertexNumber() + 1; + for (TopTools_ListOfShape::Iterator aFaceIter (anEdgeIter.Value()); aFaceIter.More(); aFaceIter.Next()) { - continue; - } - - const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Key()); - if (theUpperContinuity < GeomAbs_CN - && anEdgeIter.Value().Extent() >= 2 - && BRep_Tool::MaxContinuity (anEdge) > theUpperContinuity) - { - continue; - } - - Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf); - if (anEdgePoly.IsNull() - || anEdgePoly->Nodes().Length () < 2) - { - continue; - } - - // get edge nodes indexes from face triangulation - const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes(); - - // collect the edge nodes - Standard_Integer aSegmentEdge = aSegments->VertexNumber() + 1; - for (Standard_Integer aNodeIdx = anEdgeNodes.Lower(); aNodeIdx <= anEdgeNodes.Upper(); ++aNodeIdx) - { - // node index in face triangulation - // get node and apply location transformation to the node - const Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx); - gp_Pnt aTriNode = aTriangulation->Node (aTriIndex); - if (!aTrsf.IsIdentity()) + const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value()); + Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLoc); + if (aTriangulation.IsNull()) { - aTriNode.Transform (aTrsf); + continue; } - aSegments->AddVertex (aTriNode); - if (aNodeIdx != anEdgeNodes.Lower()) + const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Key()); + if (theUpperContinuity < GeomAbs_CN + && anEdgeIter.Value().Extent() >= 2 + && BRep_Tool::MaxContinuity (anEdge) > theUpperContinuity) { - aSegments->AddEdge ( aSegmentEdge); - aSegments->AddEdge (++aSegmentEdge); + continue; + } + + Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aLoc); + if (anEdgePoly.IsNull() + || anEdgePoly->Nodes().Length () < 2) + { + continue; + } + + // get edge nodes indexes from face triangulation + ++aFaceIndex; + const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes(); + const gp_Trsf& aTrsf = aLoc.Transformation(); + + // collect the edge nodes + Standard_Integer aSegmentEdge = aFirstNodeInFace; + for (Standard_Integer aNodeIdx = anEdgeNodes.Lower(); aNodeIdx <= anEdgeNodes.Upper(); ++aNodeIdx) + { + // node index in face triangulation + // get node and apply location transformation to the node + const Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx); + + gp_Pnt aTriNode = aTriangulation->Node (aTriIndex); + gp_Dir aNorm = aTriangulation->Normal (aTriIndex); + if (aFace.Orientation() == TopAbs_REVERSED) + { + aNorm.Reverse(); + } + if (!aLoc.IsIdentity()) + { + aTriNode.Transform (aTrsf); + aNorm.Transform (aTrsf); + } + + if (aFaceIndex == 1) + { + aSegments->AddVertex (aTriNode, aNorm); + if (aNodeIdx != anEdgeNodes.Lower()) + { + aSegments->AddEdge (aSegmentEdge); + aSegments->AddEdge (++aSegmentEdge); + } + } + else + { + gp_XYZ aNormSum; + aSegments->VertexNormal (aSegmentEdge, aNormSum.ChangeCoord (1), aNormSum.ChangeCoord (2), aNormSum.ChangeCoord (3)); + aNormSum += aNorm.XYZ(); + aNormSum.Normalize(); + aSegments->SetVertexNormal (aSegmentEdge, aNormSum.ChangeCoord (1), aNormSum.ChangeCoord (2), aNormSum.ChangeCoord (3)); + ++aSegmentEdge; + } } } } @@ -588,7 +614,13 @@ void StdPrs_ShadedShape::Add (const Handle (Prs3d_Presentation)& thePrs, if (Handle(Graphic3d_ArrayOfSegments) aBndSegments = fillFaceBoundaries (theShape, theDrawer->FaceBoundaryUpperContinuity())) { Handle(Graphic3d_Group) aPrsGrp = !theGroup.IsNull() ? theGroup : thePrs->NewGroup(); - aPrsGrp->SetGroupPrimitivesAspect (theDrawer->FaceBoundaryAspect()->Aspect()); + Handle(Graphic3d_AspectLine3d) aLineAspect = theDrawer->FaceBoundaryAspect()->Aspect(); + if (theDrawer->FaceBoundaryShadingOverride()) + { + Quantity_Color aColor = theDrawer->ShadingAspect()->Color(); + aLineAspect->SetColor (aColor); + } + aPrsGrp->SetGroupPrimitivesAspect (aLineAspect); aPrsGrp->AddPrimitiveArray (aBndSegments); } } diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 43aced25af..5824d3a32c 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -1713,6 +1713,11 @@ struct ViewerTest_AspectsChangeSet Standard_Integer ToSetTypeOfFaceBoundaryLine; Aspect_TypeOfLine TypeOfFaceBoundaryLine; + Standard_Integer ToSetFaceBoundaryShading; + Standard_Integer ToFaceBoundaryEdgeColorOverride; + Graphic3d_TypeOfShadingModel FaceBoundaryShading; + TCollection_AsciiString FaceBoundaryShadingModelName; + Standard_Integer ToSetMaxParamValue; Standard_Real MaxParamValue; @@ -1787,6 +1792,9 @@ struct ViewerTest_AspectsChangeSet FaceBoundaryWidth (1.0f), ToSetTypeOfFaceBoundaryLine(0), TypeOfFaceBoundaryLine (Aspect_TOL_SOLID), + ToSetFaceBoundaryShading (0), + ToFaceBoundaryEdgeColorOverride (0), + FaceBoundaryShading (Graphic3d_TypeOfShadingModel_DEFAULT), // ToSetMaxParamValue (0), MaxParamValue (500000), @@ -1828,6 +1836,7 @@ struct ViewerTest_AspectsChangeSet && ToSetFaceBoundaryUpperContinuity == 0 && ToSetFaceBoundaryColor == 0 && ToSetFaceBoundaryWidth == 0 + && ToSetFaceBoundaryShading == 0 && ToSetTypeOfFaceBoundaryLine == 0 && ToSetMaxParamValue == 0 && ToSetSensitivity == 0 @@ -1875,6 +1884,12 @@ struct ViewerTest_AspectsChangeSet Message::SendFail() << "Error: the free boundary width should be within [1; 10] range (specified " << FreeBoundaryWidth << ")"; isOk = Standard_False; } + if (ToSetFaceBoundaryShading == 1 + && (FaceBoundaryShading < Graphic3d_TypeOfShadingModel_DEFAULT || FaceBoundaryShading > Graphic3d_TypeOfShadingModel_PbrFacet)) + { + Message::SendFail() << "Error: unknown face boundary shading model " << FaceBoundaryShadingModelName << "."; + isOk = Standard_False; + } if (MaxParamValue < 0.0) { Message::SendFail() << "Error: the max parameter value should be greater than zero (specified " << MaxParamValue << ")"; @@ -2034,6 +2049,16 @@ struct ViewerTest_AspectsChangeSet theDrawer->FaceBoundaryAspect()->SetWidth (FaceBoundaryWidth); } } + if (ToSetFaceBoundaryShading != 0) + { + if (ToSetFaceBoundaryShading != -1 + || theDrawer->HasOwnFaceBoundaryAspect()) + { + toRecompute = theDrawer->SetupOwnFaceBoundaryAspect (aDefDrawer) || toRecompute; + theDrawer->FaceBoundaryAspect()->Aspect()->SetShadingModel (FaceBoundaryShading); + theDrawer->SetFaceBoundaryShadingOverride (ToFaceBoundaryEdgeColorOverride); + } + } if (ToSetTypeOfFaceBoundaryLine != 0) { if (ToSetTypeOfFaceBoundaryLine != -1 @@ -2389,6 +2414,17 @@ static Standard_Integer VAspects (Draw_Interpretor& theDI, if (aNames.Size() >= 2 && aNames.Value (2).IsIntegerValue()) { + if (aNames.Size() == 9 && aNames.Value (9).IsIntegerValue()) + { + if (ViewerTest::ParseShadingModel (aNames.Value (8).ToCString(), aChangeSet->FaceBoundaryShading) + && (aNames.Value (9).IsIntegerValue() == 0 || aNames.Value (9).IsIntegerValue() == 1)) + { + aChangeSet->ToSetFaceBoundaryShading = 1; + aChangeSet->ToFaceBoundaryEdgeColorOverride = aNames.Value (9).IsIntegerValue(); + aNames.Remove (9); + aNames.Remove (8); + } + } if (aNames.Size() == 7) { if (ViewerTest::ParseLineType (aNames.Value (7).ToCString(), aChangeSet->TypeOfFaceBoundaryLine)) @@ -3148,6 +3184,29 @@ static Standard_Integer VAspects (Draw_Interpretor& theDI, aChangeSet->ToSetShadingModel = -1; aChangeSet->ShadingModel = Graphic3d_TypeOfShadingModel_DEFAULT; } + else if (anArg == "-setboundaryshading") + { + aChangeSet->ToSetFaceBoundaryShading = 1; + aChangeSet->FaceBoundaryShadingModelName = theArgVec[++anArgIter]; + if (!ViewerTest::ParseShadingModel (theArgVec[anArgIter], aChangeSet->FaceBoundaryShading)) + { + Message::SendFail() << "Error: wrong syntax at " << anArg; + return 1; + } + Standard_Integer anOverrideFlag = Draw::Atoi (theArgVec[++anArgIter]); + if (!(anOverrideFlag == 0 || anOverrideFlag == 1)) + { + Message::SendFail() << "Error: wrong syntax at " << anArg; + return 1; + } + aChangeSet->ToFaceBoundaryEdgeColorOverride = anOverrideFlag; + } + else if (anArg == "-unsetboundaryshading") + { + aChangeSet->ToSetFaceBoundaryShading = -1; + aChangeSet->ToFaceBoundaryEdgeColorOverride = 0; + aChangeSet->FaceBoundaryShading = Graphic3d_TypeOfShadingModel_Unlit; + } else if (anArg == "-setinterior" || anArg == "-setinteriorstyle" || anArg == "-interior" @@ -3272,6 +3331,8 @@ static Standard_Integer VAspects (Draw_Interpretor& theDI, aChangeSet->FaceBoundaryWidth = 1.0f; aChangeSet->ToSetTypeOfFaceBoundaryLine = -1; aChangeSet->TypeOfFaceBoundaryLine = Aspect_TOL_SOLID; + aChangeSet->ToSetFaceBoundaryShading = -1; + aChangeSet->FaceBoundaryShading = Graphic3d_TypeOfShadingModel_DEFAULT; // aChangeSet->ToSetHatch = -1; aChangeSet->StdHatchStyle = -1; @@ -6804,6 +6865,8 @@ vaspects [-noupdate|-update] [name1 [name2 [...]] | -defaults] [-subshapes subna [-sensitivity {selection_mode} {value}] [-shadingModel {unlit|flat|gouraud|phong|pbr|pbr_facet}] [-unsetShadingModel] + [-setboundaryshading {unlit|flat|gouraud|phong|pbr|pbr_facet}] + [-unsetboundaryshading] [-interior {solid|hatch|hidenline|point}] [-setHatch HatchStyle] [-unsetInterior] [-faceBoundaryDraw {0|1}] [-mostContinuity {c0|g1|c1|g2|c2|c3|cn}] diff --git a/src/XDEDRAW/XDEDRAW.cxx b/src/XDEDRAW/XDEDRAW.cxx index 49d6c2685b..b557a96523 100644 --- a/src/XDEDRAW/XDEDRAW.cxx +++ b/src/XDEDRAW/XDEDRAW.cxx @@ -1197,7 +1197,7 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di, Standard_Integer argc, const char ** argv) { - if (( argc != 4 && argc < 7 ) || argc > 9) + if (( argc != 4 && argc < 7 ) || argc > 11) { di << "Usage :\n " << argv[0] << " Doc Label IsOn [R G B [LineWidth [LineStyle]]]\n" @@ -1216,7 +1216,11 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di, << " 1 - dashed \n" << " 2 - dot \n" << " 3 - dashdot\n" - << " (default is solid)"; + << " (default is solid)\n" + << " Shading - flag indicating if the boundaries\n" + << " should be shaded:" + << " 0 - no override edge color" + << " 1 - override edge color"; return 1; } @@ -1310,6 +1314,17 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di, aDrawer->SetFaceBoundaryAspect (aBoundaryAspect); + // set shading properties for face boundaries + if (argc == 11) + { + Graphic3d_TypeOfShadingModel aShadingModel; + if (ViewerTest::ParseShadingModel (argv[9], aShadingModel)) + { + aDrawer->FaceBoundaryAspect()->Aspect()->SetShadingModel (aShadingModel); + aDrawer->SetFaceBoundaryShadingOverride (Draw::Atoi (argv[10]) == 1 ? Standard_True : Standard_False); + } + } + aContext->Redisplay (anInteractive, Standard_True); return 0; diff --git a/tests/v3d/bugs/bug26072 b/tests/v3d/bugs/bug26072 new file mode 100644 index 0000000000..171790e03f --- /dev/null +++ b/tests/v3d/bugs/bug26072 @@ -0,0 +1,40 @@ +puts "========" +puts "0026072: Visualization - more realistic display of face edges" +puts "========" + +pload MODELING VISUALIZATION XDE +testreadstep [locate_data_file as1-oc-214-mat.stp] s +vclear +vinit +vdisplay s -dispmode 1 +vfit +vshowfaceboundary s -setboundaryshading phong 1 -boundarycolor 50 250 50 +vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0 +vdump $::imagedir/${::casename}_shading_1.png +vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0 +vdump $::imagedir/${::casename}_shading_2.png + +vshowfaceboundary s -setboundaryshading phong 0 -boundarycolor 50 250 50 +vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0 +vdump $::imagedir/${::casename}_noshading_1.png +vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0 +vdump $::imagedir/${::casename}_noshading_2.png + +vclear +vclose +ReadStep D [locate_data_file as1-oc-214-mat.stp] +XShow D +vfit +vsetdispmode 1 + +XShowFaceBoundary D 0:1:1:1 1 156 156 156 1 0 phong 1 +vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0 +vdump $::imagedir/${::casename}_xview_shading_1.png +vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0 +vdump $::imagedir/${::casename}_xview_shading_2.png + +XShowFaceBoundary D 0:1:1:1 1 156 156 156 1 0 phong 0 +vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0 +vdump $::imagedir/${::casename}_xview_noshading_1.png +vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0 +vdump $::imagedir/${::casename}_xview_noshading_2.png