Skip to content

Commit d6f3985

Browse files
committed
Merge pull request #182 from johnhaddon/faceNormals
OpenGL polygon shading fix
2 parents 76ab8ba + 4eb504c commit d6f3985

File tree

12 files changed

+360
-76
lines changed

12 files changed

+360
-76
lines changed

SConstruct

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,7 @@ if env["PLATFORM"] == "posix" :
11731173
# get the python link flags
11741174
if pythonEnv["PYTHON_LINK_FLAGS"]=="" :
11751175
pythonEnv["PYTHON_LINK_FLAGS"] = getPythonConfig( pythonEnv, "--ldflags" )
1176+
pythonEnv["PYTHON_LINK_FLAGS"] = pythonEnv["PYTHON_LINK_FLAGS"].replace( "Python.framework/Versions/" + pythonEnv["PYTHON_VERSION"] + "/Python", "" )
11761177

11771178
pythonEnv.Append( SHLINKFLAGS = pythonEnv["PYTHON_LINK_FLAGS"].split() )
11781179

include/IECore/MeshNormalsOp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#define IECORE_MESHNORMALSOP_H
3737

3838
#include "IECore/TypedPrimitiveOp.h"
39+
#include "IECore/NumericParameter.h"
3940

4041
namespace IECore
4142
{
@@ -57,6 +58,8 @@ class MeshNormalsOp : public MeshPrimitiveOp
5758
StringParameter * nPrimVarNameParameter();
5859
const StringParameter * nPrimVarNameParameter() const;
5960

61+
IntParameter *interpolationParameter();
62+
const IntParameter *interpolationParameter() const;
6063

6164
protected:
6265

include/IECore/PolygonAlgo.inl

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,17 @@ typename std::iterator_traits<Iterator>::value_type polygonNormal( Iterator firs
5858

5959
Vec n( 0 );
6060

61-
CircularIt v0It( first, last, first );
62-
CircularIt v1It( v0It ); v1It++;
61+
CircularIt vIt( first, last, first );
6362
do
6463
{
65-
const Vec &v0 = *v0It;
66-
const Vec &v1 = *v1It;
64+
const Vec &v0 = *vIt; ++vIt;
65+
const Vec &v1 = *vIt;
6766

6867
n.x += (v0.y - v1.y) * (v0.z + v1.z);
6968
n.y += (v0.z - v1.z) * (v0.x + v1.x);
7069
n.z += (v0.x - v1.x) * (v0.y + v1.y);
71-
72-
v0It++;
73-
v1It++;
7470
}
75-
while( v0It != first );
71+
while( vIt != first );
7672

7773
return normalized ? n.normalized() : n;
7874
}
@@ -89,19 +85,15 @@ Winding polygonWinding( Iterator first, Iterator last )
8985

9086
Real z( 0 );
9187

92-
CircularIt v0It( first, last, first );
93-
CircularIt v1It( v0It ); v1It++;
88+
CircularIt vIt( first, last, first );
9489
do
9590
{
96-
const Vec &v0 = *v0It;
97-
const Vec &v1 = *v1It;
91+
const Vec &v0 = *vIt; ++vIt;
92+
const Vec &v1 = *vIt;
9893

9994
z += (v0.x - v1.x) * (v0.y + v1.y);
100-
101-
v0It++;
102-
v1It++;
10395
}
104-
while( v0It != first );
96+
while( vIt != first );
10597

10698
return z < Real( 0 ) ? ClockwiseWinding : CounterClockwiseWinding;
10799
}

include/IECoreGL/MeshPrimitive.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ class MeshPrimitive : public Primitive
5151
IE_CORE_DECLARERUNTIMETYPEDEXTENSION( IECoreGL::MeshPrimitive, MeshPrimitiveTypeId, Primitive );
5252

5353
/// Copies of all data are taken.
54+
/// \deprecated. This constructor was being used to allow the MeshPrimitive to support
55+
/// Vertex and Varying primitive variables in addPrimitiveVariable(), but it lacks the
56+
/// information necessary to support Uniform primitive variables. In the future this
57+
/// constructor will be removed - for forwards compatibility, use a ToGLMeshConverter
58+
/// to create MeshPrimitives.
59+
/// \todo Replace this with a simple MeshPrimitive( numTriangles ) constructor, remove all
60+
/// the conversions from addPrimitiveVariable, and just rely on the work the ToGLMeshConverter
61+
/// already does.
5462
MeshPrimitive( IECore::ConstIntVectorDataPtr vertIds );
5563
virtual ~MeshPrimitive();
5664

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are
7+
// met:
8+
//
9+
// * Redistributions of source code must retain the above copyright
10+
// notice, this list of conditions and the following disclaimer.
11+
//
12+
// * Redistributions in binary form must reproduce the above copyright
13+
// notice, this list of conditions and the following disclaimer in the
14+
// documentation and/or other materials provided with the distribution.
15+
//
16+
// * Neither the name of Image Engine Design nor the names of any
17+
// other contributors to this software may be used to endorse or
18+
// promote products derived from this software without specific prior
19+
// written permission.
20+
//
21+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22+
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23+
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+
//
33+
//////////////////////////////////////////////////////////////////////////
34+
35+
#ifndef IECOREGL_MESHPRIMITIVEBINDING_H
36+
#define IECOREGL_MESHPRIMITIVEBINDING_H
37+
38+
namespace IECoreGL
39+
{
40+
41+
void bindMeshPrimitive();
42+
43+
}
44+
45+
#endif // IECOREGL_MESHPRIMITIVEBINDING_H

src/IECore/MeshNormalsOp.cpp

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
//
3333
//////////////////////////////////////////////////////////////////////////
3434

35+
#include "boost/format.hpp"
36+
3537
#include "IECore/MeshNormalsOp.h"
3638
#include "IECore/DespatchTypedData.h"
3739
#include "IECore/CompoundParameter.h"
3840

39-
#include "boost/format.hpp"
40-
4141
using namespace IECore;
4242
using namespace std;
4343

@@ -59,8 +59,19 @@ MeshNormalsOp::MeshNormalsOp() : MeshPrimitiveOp( "Calculates vertex normals for
5959
"N"
6060
);
6161

62+
IntParameter::PresetsContainer interpolationPresets;
63+
interpolationPresets.push_back( IntParameter::Preset( "Vertex", PrimitiveVariable::Vertex ) );
64+
interpolationPresets.push_back( IntParameter::Preset( "Uniform", PrimitiveVariable::Uniform ) );
65+
IntParameterPtr interpolationParameter = new IntParameter(
66+
"interpolation",
67+
"The primitive variable interpolation type for the calculated normals.",
68+
PrimitiveVariable::Vertex,
69+
interpolationPresets
70+
);
71+
6272
parameters()->addParameter( pPrimVarNameParameter );
6373
parameters()->addParameter( nPrimVarNameParameter );
74+
parameters()->addParameter( interpolationParameter );
6475
}
6576

6677
MeshNormalsOp::~MeshNormalsOp()
@@ -87,12 +98,22 @@ const StringParameter * MeshNormalsOp::nPrimVarNameParameter() const
8798
return parameters()->parameter<StringParameter>( "nPrimVarName" );
8899
}
89100

101+
IntParameter * MeshNormalsOp::interpolationParameter()
102+
{
103+
return parameters()->parameter<IntParameter>( "interpolation" );
104+
}
105+
106+
const IntParameter * MeshNormalsOp::interpolationParameter() const
107+
{
108+
return parameters()->parameter<IntParameter>( "interpolation" );
109+
}
110+
90111
struct MeshNormalsOp::CalculateNormals
91112
{
92113
typedef DataPtr ReturnType;
93114

94-
CalculateNormals( const IntVectorData * vertsPerFace, const IntVectorData * vertIds )
95-
: m_vertsPerFace( vertsPerFace ), m_vertIds( vertIds )
115+
CalculateNormals( const IntVectorData *vertsPerFace, const IntVectorData *vertIds, PrimitiveVariable::Interpolation interpolation )
116+
: m_vertsPerFace( vertsPerFace ), m_vertIds( vertIds ), m_interpolation( interpolation )
96117
{
97118
}
98119

@@ -109,39 +130,63 @@ struct MeshNormalsOp::CalculateNormals
109130
typename T::Ptr normalsData = new T;
110131
normalsData->setInterpretation( GeometricData::Normal );
111132
VecContainer &normals = normalsData->writable();
112-
normals.resize( points.size(), Vec( 0 ) );
133+
if( m_interpolation == PrimitiveVariable::Uniform )
134+
{
135+
normals.reserve( vertsPerFace.size() );
136+
}
137+
else
138+
{
139+
normals.resize( points.size(), Vec( 0 ) );
140+
}
113141

114-
// for each face, calculate its normal, and accumulate that normal onto
115-
// the normal for each of its vertices.
142+
// loop over the faces
116143
const int *vertId = &(vertIds[0]);
117144
for( vector<int>::const_iterator it = vertsPerFace.begin(); it!=vertsPerFace.end(); it++ )
118145
{
146+
// calculate the face normal. note that this method is very naive, and doesn't
147+
// cope with colinear vertices or concave faces - we could use polygonNormal() from
148+
// PolygonAlgo.h to deal with that, but currently we'd prefer to avoid the overhead.
119149
const Vec &p0 = points[*vertId];
120150
const Vec &p1 = points[*(vertId+1)];
121151
const Vec &p2 = points[*(vertId+2)];
122152

123153
Vec normal = (p2-p1).cross(p0-p1);
124154
normal.normalize();
125-
for( int i=0; i<*it; i++ )
155+
156+
if( m_interpolation == PrimitiveVariable::Uniform )
126157
{
127-
normals[*vertId] += normal;
128-
vertId++;
158+
normals.push_back( normal );
159+
vertId += *it;
160+
}
161+
else
162+
{
163+
// accumulate the face normal onto each of the vertices
164+
// for this face.
165+
for( int i=0; i<*it; ++i )
166+
{
167+
normals[*vertId] += normal;
168+
++vertId;
169+
}
129170
}
130171
}
131172

132173
// normalize each of the vertex normals
133-
for( typename VecContainer::iterator it=normals.begin(); it!=normals.end(); it++ )
174+
if( m_interpolation == PrimitiveVariable::Vertex )
134175
{
135-
it->normalize();
176+
for( typename VecContainer::iterator it=normals.begin(), eIt=normals.end(); it != eIt; ++it )
177+
{
178+
it->normalize();
179+
}
136180
}
137-
181+
138182
return normalsData;
139183
}
140184

141185
private :
142186

143187
ConstIntVectorDataPtr m_vertsPerFace;
144188
ConstIntVectorDataPtr m_vertIds;
189+
PrimitiveVariable::Interpolation m_interpolation;
145190

146191
};
147192

@@ -171,8 +216,10 @@ void MeshNormalsOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundOb
171216
throw InvalidArgumentException( e );
172217
}
173218

174-
CalculateNormals f( mesh->verticesPerFace(), mesh->vertexIds() );
219+
const PrimitiveVariable::Interpolation interpolation = static_cast<PrimitiveVariable::Interpolation>( operands->member<IntData>( "interpolation" )->readable() );
220+
221+
CalculateNormals f( mesh->verticesPerFace(), mesh->vertexIds(), interpolation );
175222
DataPtr n = despatchTypedData<CalculateNormals, TypeTraits::IsVec3VectorTypedData, HandleErrors>( pvIt->second.data, f );
176223

177-
mesh->variables[ nPrimVarNameParameter()->getTypedValue() ] = PrimitiveVariable( PrimitiveVariable::Vertex, n );
224+
mesh->variables[ nPrimVarNameParameter()->getTypedValue() ] = PrimitiveVariable( interpolation, n );
178225
}

src/IECoreGL/MeshPrimitive.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ struct MeshPrimitive::MemberData : public IECore::RefCounted
6060
IECore::ConstIntVectorDataPtr vertIds;
6161
Imath::Box3f bound;
6262

63-
/// \todo This could be removed and the ToGLMeshConverter could use FaceVaryingPromotionOp
64-
/// to convert everything to FaceVarying before being added.
63+
/// \todo This could be removed now the ToGLMeshConverter uses FaceVaryingPromotionOp
64+
/// to convert everything to FaceVarying before being added. The only reason we're even
65+
/// doing this still is in case client code is creating MeshPrimitives directly rather
66+
/// than using the converter. We should actually be able to remove the code here, and
67+
/// instead of accept vertIds in the MeshPrimitive constructor, just accept the number
68+
/// of triangles instead.
6569
class ToFaceVaryingConverter
6670
{
6771
public:
@@ -118,23 +122,23 @@ IECore::ConstIntVectorDataPtr MeshPrimitive::vertexIds() const
118122

119123
void MeshPrimitive::addPrimitiveVariable( const std::string &name, const IECore::PrimitiveVariable &primVar )
120124
{
121-
if ( primVar.interpolation==IECore::PrimitiveVariable::Vertex || primVar.interpolation==IECore::PrimitiveVariable::Varying )
125+
if( name == "P" )
122126
{
123-
if ( name == "P" )
127+
// update the bounding box.
128+
m_memberData->bound.makeEmpty();
129+
IECore::ConstV3fVectorDataPtr points = IECore::runTimeCast< IECore::V3fVectorData >( primVar.data );
130+
if( points )
124131
{
125-
// update the bounding box.
126-
m_memberData->bound.makeEmpty();
127-
IECore::ConstV3fVectorDataPtr points = IECore::runTimeCast< IECore::V3fVectorData >( primVar.data );
128-
if ( points )
132+
const std::vector<Imath::V3f> &p = points->readable();
133+
for( unsigned int i=0; i<p.size(); i++ )
129134
{
130-
const std::vector<Imath::V3f> &p = points->readable();
131-
for( unsigned int i=0; i<p.size(); i++ )
132-
{
133-
m_memberData->bound.extendBy( p[i] );
134-
}
135+
m_memberData->bound.extendBy( p[i] );
135136
}
136137
}
137-
138+
}
139+
140+
if ( primVar.interpolation==IECore::PrimitiveVariable::Vertex || primVar.interpolation==IECore::PrimitiveVariable::Varying )
141+
{
138142
MemberData::ToFaceVaryingConverter primVarConverter( m_memberData->vertIds );
139143
// convert to facevarying
140144
IECore::DataPtr newData = IECore::despatchTypedData< MemberData::ToFaceVaryingConverter, IECore::TypeTraits::IsVectorTypedData >( primVar.data, primVarConverter );

0 commit comments

Comments
 (0)