32
32
//
33
33
// ////////////////////////////////////////////////////////////////////////
34
34
35
+ #include " boost/format.hpp"
36
+
35
37
#include " IECore/MeshNormalsOp.h"
36
38
#include " IECore/DespatchTypedData.h"
37
39
#include " IECore/CompoundParameter.h"
38
40
39
- #include " boost/format.hpp"
40
-
41
41
using namespace IECore ;
42
42
using namespace std ;
43
43
@@ -59,8 +59,19 @@ MeshNormalsOp::MeshNormalsOp() : MeshPrimitiveOp( "Calculates vertex normals for
59
59
" N"
60
60
);
61
61
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
+
62
72
parameters ()->addParameter ( pPrimVarNameParameter );
63
73
parameters ()->addParameter ( nPrimVarNameParameter );
74
+ parameters ()->addParameter ( interpolationParameter );
64
75
}
65
76
66
77
MeshNormalsOp::~MeshNormalsOp ()
@@ -87,12 +98,22 @@ const StringParameter * MeshNormalsOp::nPrimVarNameParameter() const
87
98
return parameters ()->parameter <StringParameter>( " nPrimVarName" );
88
99
}
89
100
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
+
90
111
struct MeshNormalsOp ::CalculateNormals
91
112
{
92
113
typedef DataPtr ReturnType;
93
114
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 )
96
117
{
97
118
}
98
119
@@ -109,39 +130,63 @@ struct MeshNormalsOp::CalculateNormals
109
130
typename T::Ptr normalsData = new T;
110
131
normalsData->setInterpretation ( GeometricData::Normal );
111
132
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
+ }
113
141
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
116
143
const int *vertId = &(vertIds[0 ]);
117
144
for ( vector<int >::const_iterator it = vertsPerFace.begin (); it!=vertsPerFace.end (); it++ )
118
145
{
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.
119
149
const Vec &p0 = points[*vertId];
120
150
const Vec &p1 = points[*(vertId+1 )];
121
151
const Vec &p2 = points[*(vertId+2 )];
122
152
123
153
Vec normal = (p2-p1).cross (p0-p1);
124
154
normal.normalize ();
125
- for ( int i=0 ; i<*it; i++ )
155
+
156
+ if ( m_interpolation == PrimitiveVariable::Uniform )
126
157
{
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
+ }
129
170
}
130
171
}
131
172
132
173
// normalize each of the vertex normals
133
- for ( typename VecContainer::iterator it=normals. begin (); it!=normals. end (); it++ )
174
+ if ( m_interpolation == PrimitiveVariable::Vertex )
134
175
{
135
- it->normalize ();
176
+ for ( typename VecContainer::iterator it=normals.begin (), eIt=normals.end (); it != eIt; ++it )
177
+ {
178
+ it->normalize ();
179
+ }
136
180
}
137
-
181
+
138
182
return normalsData;
139
183
}
140
184
141
185
private :
142
186
143
187
ConstIntVectorDataPtr m_vertsPerFace;
144
188
ConstIntVectorDataPtr m_vertIds;
189
+ PrimitiveVariable::Interpolation m_interpolation;
145
190
146
191
};
147
192
@@ -171,8 +216,10 @@ void MeshNormalsOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundOb
171
216
throw InvalidArgumentException ( e );
172
217
}
173
218
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 );
175
222
DataPtr n = despatchTypedData<CalculateNormals, TypeTraits::IsVec3VectorTypedData, HandleErrors>( pvIt->second .data , f );
176
223
177
- mesh->variables [ nPrimVarNameParameter ()->getTypedValue () ] = PrimitiveVariable ( PrimitiveVariable::Vertex , n );
224
+ mesh->variables [ nPrimVarNameParameter ()->getTypedValue () ] = PrimitiveVariable ( interpolation , n );
178
225
}
0 commit comments