implement correct vertex normals

- use mesh vertices uv value to get correct normals from face
- remove unused normal and shading options for parts
This commit is contained in:
Stefan Tröger 2015-02-22 09:27:55 +01:00 committed by wmayer
parent d29d62b4ab
commit d5ee7a6efe
3 changed files with 114 additions and 120 deletions

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>610</width>
<width>525</width>
<height>339</height>
</rect>
</property>
@ -53,26 +53,7 @@
<property name="spacing">
<number>6</number>
</property>
<item row="4" column="0" colspan="3">
<widget class="Gui::PrefCheckBox" name="prefCheckBox8">
<property name="toolTip">
<string>Defines the appearance of surfaces</string>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;/head&gt;&lt;body style=&quot; white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;&quot;&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Flat shading/Phong shading&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;With flat shading the surface normals are not defined per vertex that leads to a unreal appearance for curved surfaces while using Phong shading leads to a smoother appearance. &lt;/p&gt;&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If this option is unset Phong shading is used, if it is set flat shading is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Do not define normal per vertex</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>NoPerVertexNormals</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Part</cstring>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="2" colspan="2">
<item row="0" column="0" rowspan="2" colspan="2">
<widget class="QLabel" name="textLabel1">
<property name="toolTip">
<string>Defines the deviation of tessellation to the actual surface</string>
@ -85,21 +66,7 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="4">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;/head&gt;&lt;body style=&quot; white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;&quot;&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Hint&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;Defining the normals per vertex is also called &lt;span style=&quot; font-style:italic;&quot;&gt;Phong shading&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt; font-style:italic;&quot;&gt;&lt;span style=&quot; font-style:normal;&quot;&gt;while defining the normals per face is called &lt;/span&gt;Flat shading&lt;span style=&quot; font-style:normal;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textLabel1_3_3_2">
<property name="text">
<string>View smoothing</string>
</property>
</widget>
</item>
<item row="2" column="3">
<item row="1" column="2">
<widget class="Gui::PrefDoubleSpinBox" name="maxDeviation">
<property name="suffix">
<string> %</string>
@ -127,70 +94,6 @@
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="Gui::PrefCheckBox" name="prefCheckBox3">
<property name="toolTip">
<string>This will slow down render speed but will lead to nicer results</string>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;/head&gt;&lt;body style=&quot; white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;&quot;&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;High-quality normals&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This will slow down render speed but will lead to nicer results.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Using high-quality normals</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>QualityNormals</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Part</cstring>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="2" colspan="2">
<widget class="Line" name="line2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::HLine</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="textLabel1_3">
<property name="text">
<string>View accuracy / Performance</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="3">
<widget class="Line" name="line2_2_2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::HLine</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -200,11 +103,6 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>

View File

@ -70,8 +70,6 @@ void DlgSettings3DViewPart::on_maxDeviation_valueChanged(double v)
void DlgSettings3DViewPart::saveSettings()
{
ui->maxDeviation->onSave();
ui->prefCheckBox8->onSave();
ui->prefCheckBox3->onSave();
// search for Part view providers and apply the new settings
std::vector<App::Document*> docs = App::GetApplication().getDocuments();
@ -87,8 +85,6 @@ void DlgSettings3DViewPart::saveSettings()
void DlgSettings3DViewPart::loadSettings()
{
ui->maxDeviation->onRestore();
ui->prefCheckBox8->onRestore();
ui->prefCheckBox3->onRestore();
}
/**

View File

@ -35,6 +35,7 @@
# include <BRepTools.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <GeomLib.hxx>
# include <GeomAbs_CurveType.hxx>
# include <GeomAbs_SurfaceType.hxx>
# include <Geom_BezierCurve.hxx>
@ -47,6 +48,7 @@
# include <Handle_Poly_Triangulation.hxx>
# include <Poly_Array1OfTriangle.hxx>
# include <Poly_Triangulation.hxx>
# include <Poly_Connect.hxx>
# include <Standard_Version.hxx>
# include <TColgp_Array1OfPnt.hxx>
# include <TopoDS.hxx>
@ -61,7 +63,13 @@
# include <TopTools_IndexedMapOfShape.hxx>
# include <Poly_PolygonOnTriangulation.hxx>
# include <TColStd_Array1OfInteger.hxx>
# include <TColgp_Array1OfDir.hxx>
# include <TColgp_Array1OfPnt2d.hxx>
# include <TopTools_ListOfShape.hxx>
# include <TShort_Array1OfShortReal.hxx>
# include <TShort_HArray1OfShortReal.hxx>
# include <Precision.hxx>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/details/SoLineDetail.h>
@ -119,6 +127,94 @@ using namespace PartGui;
PROPERTY_SOURCE(PartGui::ViewProviderPartExt, Gui::ViewProviderGeometryObject)
void GetNormals(const TopoDS_Face& theFace,
const Handle(Poly_Triangulation)& aPolyTri,
TColgp_Array1OfDir& theNormals)
{
Poly_Connect thePolyConnect(aPolyTri);
const TColgp_Array1OfPnt& aNodes = aPolyTri->Nodes();
if(aPolyTri->HasNormals())
{
// normals pre-computed in triangulation structure
const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
const Standard_ShortReal* aNormArr = &(aNormals.Value(aNormals.Lower()));
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
const gp_Dir aNorm(aNormArr[anId + 0],
aNormArr[anId + 1],
aNormArr[anId + 2]);
theNormals(aNodeIter) = aNorm;
}
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
return;
}
// take in face the surface location
const TopoDS_Face aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aZeroFace);
const Standard_Real aTol = Precision::Confusion();
Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal(1, aPolyTri->NbNodes() * 3);
const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
const TColgp_Array1OfPnt2d* aNodesUV = aPolyTri->HasUVNodes() && !aSurf.IsNull()
? &aPolyTri->UVNodes()
: NULL;
Standard_Integer aTri[3];
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
// try to retrieve normal from real surface first, when UV coordinates are available
if(aNodesUV == NULL
|| GeomLib::NormEstim(aSurf, aNodesUV->Value(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
{
// compute flat normals
gp_XYZ eqPlan(0.0, 0.0, 0.0);
for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
{
aTriangles(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
const gp_XYZ v1(aNodes(aTri[1]).Coord() - aNodes(aTri[0]).Coord());
const gp_XYZ v2(aNodes(aTri[2]).Coord() - aNodes(aTri[1]).Coord());
const gp_XYZ vv = v1 ^ v2;
const Standard_Real aMod = vv.Modulus();
if(aMod >= aTol)
{
eqPlan += vv / aMod;
}
}
const Standard_Real aModMax = eqPlan.Modulus();
theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
}
const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
aNormals->SetValue(anId + 1, (Standard_ShortReal)theNormals(aNodeIter).X());
aNormals->SetValue(anId + 2, (Standard_ShortReal)theNormals(aNodeIter).Y());
aNormals->SetValue(anId + 3, (Standard_ShortReal)theNormals(aNodeIter).Z());
}
aPolyTri->SetNormals(aNormals);
if(theFace.Orientation() == TopAbs_REVERSED)
{
for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
theNormals.ChangeValue(aNodeIter).Reverse();
}
}
}
//**************************************************************************
// Construction/Destruction
@ -765,6 +861,9 @@ void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape)
// cycling through the poly mesh
const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
TColgp_Array1OfDir Normals (Nodes.Lower(), Nodes.Upper());
GetNormals(actFace, mesh, Normals);
for (int g=1;g<=nbTriInFace;g++) {
// Get the triangle
Standard_Integer N1,N2,N3;
@ -780,22 +879,23 @@ void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape)
// get the 3 points of this triangle
gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
// transform the vertices to the place of the face
if (!identity) {
// get the 3 normals of this triangle
gp_Dir NV1(Normals(N1)), NV2(Normals(N2)), NV3(Normals(N3));
// transform the vertices and normals to the place of the face
if(!identity) {
V1.Transform(myTransf);
V2.Transform(myTransf);
V3.Transform(myTransf);
NV1.Transform(myTransf);
NV2.Transform(myTransf);
NV3.Transform(myTransf);
}
// calculating per vertex normals
// Calculate triangle normal
gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z());
gp_Vec Normal = (v2-v1)^(v3-v1);
// add the triangle normal to the vertex normal for all points of this triangle
norms[faceNodeOffset+N1-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
norms[faceNodeOffset+N2-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
norms[faceNodeOffset+N3-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
// add the normals for all points of this triangle
norms[faceNodeOffset+N1-1] += SbVec3f(NV1.X(),NV1.Y(),NV1.Z());
norms[faceNodeOffset+N2-1] += SbVec3f(NV2.X(),NV2.Y(),NV2.Z());
norms[faceNodeOffset+N3-1] += SbVec3f(NV3.X(),NV3.Y(),NV3.Z());
// set the vertices
verts[faceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));