1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-04 18:06:22 +03:00

0024521: Visualization - automatic back face culling is not turned on for Solids packed into compound

StdPrs_ToolShadedShape::IsClosed():
- return true if shape is closed Solid (NOT just free closed Shell)
- accept compound of closed Solids as well
- ignore Solids with incomplete triangulation

TKOpenGl, automatically disable back face culling when:
- clipping/capping planes are in effect
- for translucent objects

Update bug23227 test case (now back faces are clipped).

OpenGl_Workspace::AspectFace() - disable culling in case of hatched style
This commit is contained in:
kgv 2014-01-16 21:09:20 +04:00 committed by bugmaster
parent fd03ee4b3b
commit 3b1817a9e2
10 changed files with 316 additions and 143 deletions

View File

@ -44,10 +44,11 @@ struct TEL_COLOUR
};
typedef TEL_COLOUR* tel_colour;
typedef enum
typedef enum
{
TelCullNone,
TelCullFront,
TelCullUndefined = -1,
TelCullNone = 0,
TelCullFront,
TelCullBack
} TelCullMode;

View File

@ -27,9 +27,9 @@ namespace
// purpose :
// =======================================================================
OpenGl_Clipping::OpenGl_Clipping ()
: myPlanes(),
myPlaneStates(),
myEmptyPlaneIds (new Aspect_GenId (GL_CLIP_PLANE0, GL_CLIP_PLANE5))
: myEmptyPlaneIds (new Aspect_GenId (GL_CLIP_PLANE0, GL_CLIP_PLANE5)),
myNbClipping (0),
myNbCapping (0)
{}
// =======================================================================
@ -40,6 +40,8 @@ void OpenGl_Clipping::Init (const Standard_Integer theMaxPlanes)
{
myPlanes.Clear();
myPlaneStates.Clear();
myNbClipping = 0;
myNbCapping = 0;
Standard_Integer aLowerId = GL_CLIP_PLANE0;
Standard_Integer aUpperId = GL_CLIP_PLANE0 + theMaxPlanes - 1;
myEmptyPlaneIds = new Aspect_GenId (aLowerId, aUpperId);
@ -104,6 +106,15 @@ void OpenGl_Clipping::Add (Graphic3d_SequenceOfHClipPlane& thePlanes, const Equa
glEnable ((GLenum)anID);
glClipPlane ((GLenum)anID, aPlane->GetEquation());
if (aPlane->IsCapping())
{
++myNbCapping;
}
else
{
++myNbClipping;
}
aPlaneIt.Next();
}
@ -129,10 +140,22 @@ void OpenGl_Clipping::Remove (const Graphic3d_SequenceOfHClipPlane& thePlanes)
}
Standard_Integer anID = myPlaneStates.Find (aPlane).ContextID;
PlaneProps& aProps = myPlaneStates.ChangeFind (aPlane);
if (aProps.IsEnabled)
{
glDisable ((GLenum)anID);
if (aPlane->IsCapping())
{
--myNbCapping;
}
else
{
--myNbClipping;
}
}
myEmptyPlaneIds->Free (anID);
myPlaneStates.UnBind (aPlane);
glDisable ((GLenum)anID);
}
// renew collection of planes
@ -173,10 +196,26 @@ void OpenGl_Clipping::SetEnabled (const Handle(Graphic3d_ClipPlane)& thePlane,
if (theIsEnabled)
{
glEnable (anID);
if (thePlane->IsCapping())
{
++myNbCapping;
}
else
{
++myNbClipping;
}
}
else
{
glDisable (anID);
if (thePlane->IsCapping())
{
--myNbCapping;
}
else
{
--myNbClipping;
}
}
aProps.IsEnabled = theIsEnabled;

View File

@ -81,6 +81,24 @@ public: //! @name non-modifying getters
return myPlaneStates.Find (thePlane).IsEnabled;
}
//! @return true if there are enabled clipping planes (NOT capping)
inline Standard_Boolean IsClippingOn() const
{
return myNbClipping > 0;
}
//! @return true if there are enabled capping planes
inline Standard_Boolean IsCappingOn() const
{
return myNbCapping > 0;
}
//! @return true if there are enabled clipping or capping planes
inline Standard_Boolean IsClippingOrCappingOn() const
{
return (myNbClipping + myNbCapping) > 0;
}
public: //! @name clipping state modification commands
//! Add planes to the context clipping at the specified system of coordinates.
@ -198,9 +216,11 @@ private:
typedef NCollection_DataMap<Handle(Graphic3d_ClipPlane), PlaneProps> OpenGl_MapOfPlaneStates;
typedef NCollection_Handle<Aspect_GenId> OpenGl_EmptyPlaneIds;
Graphic3d_SequenceOfHClipPlane myPlanes; //!< defined clipping planes.
OpenGl_MapOfPlaneStates myPlaneStates; //!< map of clip planes bound for the props.
OpenGl_EmptyPlaneIds myEmptyPlaneIds; //!< generator of empty ids.
Graphic3d_SequenceOfHClipPlane myPlanes; //!< defined clipping planes
OpenGl_MapOfPlaneStates myPlaneStates; //!< map of clip planes bound for the props
OpenGl_EmptyPlaneIds myEmptyPlaneIds; //!< generator of empty ids
Standard_Boolean myNbClipping; //!< number of enabled clipping-only planes (NOT capping)
Standard_Boolean myNbCapping; //!< number of enabled capping planes
private:

View File

@ -166,6 +166,7 @@ OpenGl_Workspace::OpenGl_Workspace (const Handle(OpenGl_Display)& theDisplay,
TextParam_applied (NULL),
ViewMatrix_applied (&myDefaultMatrix),
StructureMatrix_applied (&myDefaultMatrix),
myCullingMode (TelCullUndefined),
myModelViewMatrix (myDefaultMatrix),
PolygonOffset_applied (NULL)
{
@ -269,6 +270,7 @@ void OpenGl_Workspace::ResetAppliedAspect()
TextParam_set = &myDefaultTextParam;
TextParam_applied = NULL;
PolygonOffset_applied = NULL;
myCullingMode = TelCullUndefined;
AspectLine(Standard_True);
AspectFace(Standard_True);

View File

@ -439,9 +439,10 @@ protected: //! @name fields related to status
const OpenGl_Matrix* ViewMatrix_applied;
const OpenGl_Matrix* StructureMatrix_applied;
OpenGl_Material myMatFront; //!< current front material state (cached to reduce GL context updates)
OpenGl_Material myMatBack; //!< current back material state
OpenGl_Material myMatTmp; //!< temporary variable
OpenGl_Material myMatFront; //!< current front material state (cached to reduce GL context updates)
OpenGl_Material myMatBack; //!< current back material state
OpenGl_Material myMatTmp; //!< temporary variable
TelCullMode myCullingMode; //!< back face culling mode, applied from face aspect
//! Model matrix with applied structure transformations
OpenGl_Matrix myModelViewMatrix;

View File

@ -319,7 +319,55 @@ const OpenGl_AspectLine * OpenGl_Workspace::AspectLine(const Standard_Boolean Wi
const OpenGl_AspectFace* OpenGl_Workspace::AspectFace (const Standard_Boolean theToApply)
{
if (!theToApply || (AspectFace_set == AspectFace_applied))
if (!theToApply)
{
return AspectFace_set;
}
if (!ActiveView()->Backfacing())
{
// manage back face culling mode, disable culling when clipping is enabled
TelCullMode aCullingMode = (myGlContext->Clipping().IsClippingOrCappingOn()
|| AspectFace_set->InteriorStyle() == Aspect_IS_HATCH)
? TelCullNone
: (TelCullMode )AspectFace_set->CullingMode();
if (aCullingMode != TelCullNone
&& myUseTransparency && !(NamedStatus & OPENGL_NS_2NDPASSDO))
{
// disable culling in case of translucent shading aspect
if (AspectFace_set->IntFront().trans != 1.0f)
{
aCullingMode = TelCullNone;
}
}
if (myCullingMode != aCullingMode)
{
myCullingMode = aCullingMode;
switch (myCullingMode)
{
case TelCullNone:
case TelCullUndefined:
{
glDisable (GL_CULL_FACE);
break;
}
case TelCullFront:
{
glCullFace (GL_FRONT);
glEnable (GL_CULL_FACE);
break;
}
case TelCullBack:
{
glCullFace (GL_BACK);
glEnable (GL_CULL_FACE);
break;
}
}
}
}
if (AspectFace_set == AspectFace_applied)
{
return AspectFace_set;
}
@ -365,34 +413,6 @@ const OpenGl_AspectFace* OpenGl_Workspace::AspectFace (const Standard_Boolean th
}
}
if (!ActiveView()->Backfacing())
{
const Tint aCullingMode = AspectFace_set->CullingMode();
if (AspectFace_applied == NULL || AspectFace_applied->CullingMode() != aCullingMode)
{
switch ((TelCullMode )aCullingMode)
{
case TelCullNone:
{
glDisable (GL_CULL_FACE);
break;
}
case TelCullFront:
{
glCullFace (GL_FRONT);
glEnable (GL_CULL_FACE);
break;
}
case TelCullBack:
{
glCullFace (GL_BACK);
glEnable (GL_CULL_FACE);
break;
}
}
}
}
// Aspect_POM_None means: do not change current settings
if ((AspectFace_set->PolygonOffset().mode & Aspect_POM_None) != Aspect_POM_None)
{

View File

@ -100,7 +100,7 @@ namespace
Standard_Real aUmin (0.0), aUmax (0.0), aVmin (0.0), aVmax (0.0), dUmax (0.0), dVmax (0.0);
// precision for compare square distances
const double aPreci = Precision::SquareConfusion();
const Standard_Real aPreci = Precision::SquareConfusion();
if (!theDrawer->ShadingAspectGlobal())
{
@ -126,99 +126,102 @@ namespace
nbVertices += T->NbNodes();
}
}
if (nbVertices > 2 && nbTriangles > 0)
if (nbVertices < 3
|| nbTriangles <= 0)
{
Handle(Graphic3d_ArrayOfTriangles) aPArray
= new Graphic3d_ArrayOfTriangles (nbVertices, 3 * nbTriangles,
Standard_True, Standard_False, theHasTexels, Standard_True);
for (SST.Init (theShape); SST.MoreFace(); SST.NextFace())
return Standard_False;
}
Handle(Graphic3d_ArrayOfTriangles) aPArray
= new Graphic3d_ArrayOfTriangles (nbVertices, 3 * nbTriangles,
Standard_True, Standard_False, theHasTexels, Standard_True);
for (SST.Init (theShape); SST.MoreFace(); SST.NextFace())
{
const TopoDS_Face& aFace = SST.CurrentFace();
T = SST.Triangulation (aFace, aLoc);
if (T.IsNull())
{
const TopoDS_Face& aFace = SST.CurrentFace();
T = SST.Triangulation (aFace, aLoc);
if (T.IsNull())
continue;
}
const gp_Trsf& aTrsf = aLoc.Transformation();
Poly_Connect pc (T);
// Extracts vertices & normals from nodes
const TColgp_Array1OfPnt& aNodes = T->Nodes();
const TColgp_Array1OfPnt2d& aUVNodes = T->UVNodes();
TColgp_Array1OfDir aNormals (aNodes.Lower(), aNodes.Upper());
SST.Normal (aFace, pc, aNormals);
if (theHasTexels)
{
BRepTools::UVBounds (aFace, aUmin, aUmax, aVmin, aVmax);
dUmax = (aUmax - aUmin);
dVmax = (aVmax - aVmin);
}
decal = aPArray->VertexNumber();
for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
p = aNodes (aNodeIter);
if (!aLoc.IsIdentity())
{
p.Transform (aTrsf);
aNormals (aNodeIter).Transform (aTrsf);
}
if (theHasTexels && aUVNodes.Upper() == aNodes.Upper())
{
const gp_Pnt2d aTexel = gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(),
(-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y());
aPArray->AddVertex (p, aNormals (aNodeIter), aTexel);
}
else
{
aPArray->AddVertex (p, aNormals (aNodeIter));
}
}
// Fill array with vertex and edge visibility info
const Poly_Array1OfTriangle& aTriangles = T->Triangles();
for (Standard_Integer aTriIter = 1; aTriIter <= T->NbTriangles(); ++aTriIter)
{
pc.Triangles (aTriIter, t[0], t[1], t[2]);
if (SST.Orientation (aFace) == TopAbs_REVERSED)
aTriangles (aTriIter).Get (n[0], n[2], n[1]);
else
aTriangles (aTriIter).Get (n[0], n[1], n[2]);
gp_Pnt P1 = aNodes (n[0]);
gp_Pnt P2 = aNodes (n[1]);
gp_Pnt P3 = aNodes (n[2]);
gp_Vec V1 (P1, P2);
if (V1.SquareMagnitude() <= aPreci)
{
continue;
}
const gp_Trsf& aTrsf = aLoc.Transformation();
Poly_Connect pc (T);
// Extracts vertices & normals from nodes
const TColgp_Array1OfPnt& aNodes = T->Nodes();
const TColgp_Array1OfPnt2d& aUVNodes = T->UVNodes();
TColgp_Array1OfDir aNormals (aNodes.Lower(), aNodes.Upper());
SST.Normal (aFace, pc, aNormals);
if (theHasTexels)
gp_Vec V2 (P2, P3);
if (V2.SquareMagnitude() <= aPreci)
{
BRepTools::UVBounds (aFace, aUmin, aUmax, aVmin, aVmax);
dUmax = (aUmax - aUmin);
dVmax = (aVmax - aVmin);
continue;
}
decal = aPArray->VertexNumber();
for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
gp_Vec V3 (P3, P1);
if (V3.SquareMagnitude() <= aPreci)
{
p = aNodes (aNodeIter);
if (!aLoc.IsIdentity())
{
p.Transform (aTrsf);
aNormals (aNodeIter).Transform (aTrsf);
}
if (theHasTexels && aUVNodes.Upper() == aNodes.Upper())
{
const gp_Pnt2d aTexel = gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(),
(-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y());
aPArray->AddVertex (p, aNormals (aNodeIter), aTexel);
}
else
{
aPArray->AddVertex (p, aNormals (aNodeIter));
}
continue;
}
// Fill parray with vertex and edge visibillity info
const Poly_Array1OfTriangle& aTriangles = T->Triangles();
for (Standard_Integer aTriIter = 1; aTriIter <= T->NbTriangles(); ++aTriIter)
V1.Normalize();
V2.Normalize();
V1.Cross (V2);
if (V1.SquareMagnitude() > aPreci)
{
pc.Triangles (aTriIter, t[0], t[1], t[2]);
if (SST.Orientation (aFace) == TopAbs_REVERSED)
aTriangles (aTriIter).Get (n[0], n[2], n[1]);
else
aTriangles (aTriIter).Get (n[0], n[1], n[2]);
gp_Pnt P1 = aNodes (n[0]);
gp_Pnt P2 = aNodes (n[1]);
gp_Pnt P3 = aNodes (n[2]);
gp_Vec V1 (P1, P2);
if (V1.SquareMagnitude() <= aPreci)
{
continue;
}
gp_Vec V2 (P2, P3);
if (V2.SquareMagnitude() <= aPreci)
{
continue;
}
gp_Vec V3 (P3, P1);
if (V3.SquareMagnitude() <= aPreci)
{
continue;
}
V1.Normalize();
V2.Normalize();
V1.Cross (V2);
if (V1.SquareMagnitude() > aPreci)
{
aPArray->AddEdge (n[0] + decal, t[0] == 0);
aPArray->AddEdge (n[1] + decal, t[1] == 0);
aPArray->AddEdge (n[2] + decal, t[2] == 0);
}
aPArray->AddEdge (n[0] + decal, t[0] == 0);
aPArray->AddEdge (n[1] + decal, t[1] == 0);
aPArray->AddEdge (n[2] + decal, t[2] == 0);
}
}
Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPArray);
}
Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPArray);
return Standard_True;
}

View File

@ -25,14 +25,16 @@ uses
Location from TopLoc
is
IsClosed(myclass; aShape: Shape from TopoDS) returns Boolean from Standard;
IsClosed (myclass; theShape : Shape from TopoDS) returns Boolean from Standard;
---Purpose: Checks back faces visibility for specified shape (to activate back-face culling).
-- @return true if shape is closed Solid or compound of closed Solids.
Triangulation(myclass; aFace: Face from TopoDS;
loc : out Location from TopLoc)
returns Triangulation from Poly;
Normal(myclass; aFace: Face from TopoDS;
PC : in out Connect from Poly;
Nor : out Array1OfDir from TColgp);
end ToolShadedShape from StdPrs;

View File

@ -32,13 +32,99 @@
#include <TShort_HArray1OfShortReal.hxx>
#include <TShort_Array1OfShortReal.hxx>
namespace
{
//=======================================================================
//function : isTriangulated
//purpose : Returns true if all faces within shape are triangulated.
// Same as BRepTools::Triangulation() but without extra checks.
//=======================================================================
static Standard_Boolean isTriangulated (const TopoDS_Shape& theShape)
{
TopLoc_Location aLocDummy;
for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
{
const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current());
const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation (aFace, aLocDummy);
if (aTri.IsNull())
{
return Standard_False;
}
}
return Standard_True;
}
}
//=======================================================================
//function : IsClosed
//purpose :
//=======================================================================
Standard_Boolean StdPrs_ToolShadedShape::IsClosed (const TopoDS_Shape& theShape)
{
return theShape.Closed();
if (theShape.IsNull())
{
return Standard_True;
}
switch (theShape.ShapeType())
{
case TopAbs_COMPOUND:
case TopAbs_COMPSOLID:
default:
{
// check that compound consists of closed solids
for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
{
const TopoDS_Shape& aShape = anIter.Value();
if (!IsClosed (aShape))
{
return Standard_False;
}
}
return Standard_True;
}
case TopAbs_SOLID:
{
for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
{
const TopoDS_Shape& aShape = anIter.Value();
if (aShape.IsNull())
{
continue;
}
if (aShape.ShapeType() == TopAbs_SHELL
&& !aShape.Closed())
{
return Standard_False;
}
else if (aShape.ShapeType() == TopAbs_FACE)
{
// invalid solid
return Standard_False;
}
else if (!isTriangulated (aShape))
{
// mesh contains holes
return Standard_False;
}
}
return Standard_True;
}
case TopAbs_SHELL:
case TopAbs_FACE:
{
// free faces / shell are not allowed
return Standard_False;
}
case TopAbs_WIRE:
case TopAbs_EDGE:
case TopAbs_VERTEX:
{
// ignore
return Standard_True;
}
}
}
//=======================================================================

View File

@ -1,19 +1,19 @@
puts "============"
puts "OCC23227"
puts "New Draw Harness command to estimate current geometry complexity of OpenGL scene"
puts "============"
puts ""
#######################################################################
# New Draw Harness command to estimate current geometry complexity of OpenGL scene
#######################################################################
set BugNumber OCC23227
box b 1 2 3
vinit
vinit View1
vclear
vdisplay b
vsetdispmode 1
vfit
set vfeedback1 [vfeedback]
vdump $imagedir/${casename}_box.png
vclear
set vfeedback2 [vfeedback]
@ -24,17 +24,16 @@ set IndexTriangles1 [lsearch ${vfeedback1} Triangles:]
set IndexTriangles2 [lsearch ${vfeedback2} Triangles:]
if { ${llength_vfeedback1} < 36 || ${llength_vfeedback2} < 36 || ${IndexTriangles1} < 0 || ${IndexTriangles2} < 0 } {
puts "Bad format of vfeedback command"
puts "Faulty ${BugNumber}"
puts "Bad format of vfeedback command"
puts "Faulty ${BugNumber}"
} else {
set Triangles1 [lindex ${vfeedback1} ${IndexTriangles1}+1]
set Triangles2 [lindex ${vfeedback2} ${IndexTriangles1}+1]
if { ${Triangles1} == 12 && ${Triangles2} == 0 } {
puts "OK ${BugNumber}"
} else {
puts "Faulty ${BugNumber}"
}
set Triangles1 [lindex ${vfeedback1} ${IndexTriangles1}+1]
set Triangles2 [lindex ${vfeedback2} ${IndexTriangles1}+1]
if { ${Triangles1} == 6 && ${Triangles2} == 0 } {
puts "OK ${BugNumber}"
} else {
puts "Faulty ${BugNumber}"
}
}
set only_screen 1