2
// Copyright ļæ½ 1997 - 2001, Paul C. Gregory
4
// Contact: pgregory@aqsis.com
6
// This library is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU General Public
8
// License as published by the Free Software Foundation; either
9
// version 2 of the License, or (at your option) any later version.
11
// This library is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
// General Public License for more details.
16
// You should have received a copy of the GNU General Public
17
// License along with this library; if not, write to the Free Software
18
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
\brief Declares the classes for subdivision surfaces.
23
\author Paul C. Gregory (pgregory@aqsis.com)
27
#ifndef SUBDIVISION2_H_LOADED
28
#define SUBDIVISION2_H_LOADED
37
START_NAMESPACE( Aqsis )
39
//------------------------------------------------------------------------------
41
* Container for the topology description of a mesh.
42
* Holds information about which Laths represent which facets and vertices, and
43
* provides functions to build topology data structures from unstructured meshes.
46
class CqSubdivision2 : public CqMotionSpec<boost::shared_ptr<CqPolygonPoints> >
53
CqSubdivision2( const boost::shared_ptr<CqPolygonPoints>& pPoints );
56
virtual ~CqSubdivision2();
59
CqString className() const { return CqString("CqSubdivision2"); }
62
CqLath* pFacet(TqInt iIndex);
63
CqLath* pVertex(TqInt iIndex);
65
/// Get the number of faces representing this topology.
66
TqInt cFacets() const {return(m_apFacets.size());}
67
/// Get the number of laths representing this topology.
68
TqInt cLaths() const {return(m_apLaths.size());}
69
/// Get the number of faces representing this topology.
70
TqInt cVertices() const {return(m_aapVertices.size());}
72
/// Get a refrence to the array of autoatically generated laths.
73
const std::vector<CqLath*>& apLaths() const
76
/// Get pointer to the vertex storage class
77
boost::shared_ptr<CqPolygonPoints> pPoints( TqInt TimeIndex = 0 ) const
79
return ( GetMotionObject( Time( TimeIndex ) ) );
82
void Prepare(TqInt cVerts);
83
CqLath* AddFacet(TqInt cVerts, TqInt* pIndices, TqInt iFVIndex);
85
void SubdivideFace(CqLath* pFace, std::vector<CqLath*>& apSubFaces);
86
TqBool CanUsePatch( CqLath* pFace );
87
void SetInterpolateBoundary( TqBool state = TqTrue )
89
m_bInterpolateBoundary = state;
91
TqBool isInterpolateBoundary( ) const
93
return( m_bInterpolateBoundary );
95
void SetHoleFace( TqInt iFaceIndex )
97
m_mapHoles[ iFaceIndex ] = TqTrue;
99
TqBool isHoleFace( TqInt iFaceIndex ) const
101
return( m_mapHoles.find( iFaceIndex ) != m_mapHoles.end() );
103
void AddSharpEdge( CqLath* pLath, TqFloat Sharpness )
105
m_mapSharpEdges[pLath] = Sharpness;
107
TqFloat EdgeSharpness( CqLath* pLath )
109
if( m_mapSharpEdges.find( pLath ) != m_mapSharpEdges.end() )
110
return( m_mapSharpEdges[ pLath ] );
113
void AddSharpCorner( CqLath* pLath, TqFloat Sharpness )
115
std::vector<CqLath*> aQve;
117
std::vector<CqLath*>::iterator iVE;
118
for( iVE = aQve.begin(); iVE != aQve.end(); iVE++ )
119
m_mapSharpCorners[(*iVE)] = Sharpness;
121
TqFloat CornerSharpness( CqLath* pLath )
123
if( m_mapSharpCorners.find( pLath ) != m_mapSharpCorners.end() )
124
return( m_mapSharpCorners[ pLath ] );
128
void AddVertex(CqLath* pVertex, TqInt& iVIndex, TqInt& iFVIndex);
129
template<class TypeA, class TypeB>
130
void CreateVertex(CqParameterTyped<TypeA, TypeB>* pParam, CqLath* pVertex, TqInt iIndex)
132
TqInt arraysize = 0, arrayindex;
133
arraysize = pParam->Count();
134
for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
136
TypeA S = TypeA(0.0f);
137
TypeA Q = TypeA(0.0f);
138
TypeA R = TypeA(0.0f);
141
if(pParam->Class() == class_vertex /*|| pParam->Class() == class_facevarying*/)
143
// Get a pointer to the appropriate index accessor function on CqLath based on class.
144
TqInt (CqLath::*IndexFunction)() const;
145
if( pParam->Class() == class_vertex )
146
IndexFunction = &CqLath::VertexIndex;
148
IndexFunction = &CqLath::FaceVertexIndex;
150
// Determine if we have a boundary vertex.
151
if( pVertex->isBoundaryVertex() )
153
// The vertex is on a boundary.
154
/// \note If "interpolateboundary" is not specified, we will never see this as
155
/// the boundary facets aren't rendered. So we don't need to check for "interpolateboundary" here.
156
std::vector<CqLath*> apQve;
158
// Is the valence == 2 ?
159
if( apQve.size() == 2 )
161
// Yes, boundary with valence 2 is corner.
162
pParam->pValue( iIndex )[arrayindex] = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
166
// No, boundary is average of two adjacent boundary edges, and original point.
167
// Get the midpoints of the adjacent boundary edges
168
std::vector<CqLath*> aQve;
169
pVertex->Qve( aQve );
171
TqInt cBoundaryEdges = 0;
172
std::vector<CqLath*>::iterator iE;
173
for( iE = aQve.begin(); iE != aQve.end(); iE++ )
175
// Only consider the boundary edges.
176
if( NULL == (*iE)->ec() )
178
if( (*iE)->VertexIndex() == (pVertex->*IndexFunction)() )
179
R += pParam->pValue( ((*iE)->ccf()->*IndexFunction)() )[arrayindex];
181
R += pParam->pValue( ((*iE)->*IndexFunction)() )[arrayindex];
185
assert( cBoundaryEdges == 2 );
187
// Get the current vertex;
188
S = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
189
pParam->pValue( iIndex )[arrayindex] = static_cast<TypeA>( ( R + ( S * 6.0f ) ) / 8.0f );
194
// Check if a sharp corner vertex.
195
if( CornerSharpness( pVertex ) > 0.0f )
197
pParam->pValue( iIndex )[arrayindex] = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
201
// Check if crease vertex.
202
std::vector<CqLath*> aQve;
203
pVertex->Qve( aQve );
205
CqLath* hardEdge1 = NULL;
206
CqLath* hardEdge2 = NULL;
207
CqLath* hardEdge3 = NULL;
209
std::vector<CqLath*>::iterator iEdge;
210
for( iEdge = aQve.begin(); iEdge != aQve.end(); iEdge++ )
212
float h = EdgeSharpness( (*iEdge) );
213
if( hardEdge1 == NULL || h > EdgeSharpness(hardEdge1) )
215
hardEdge3 = hardEdge2;
216
hardEdge2 = hardEdge1;
219
else if( hardEdge2 == NULL || h > EdgeSharpness(hardEdge2) )
221
hardEdge3 = hardEdge2;
224
else if( hardEdge3 == NULL || h > EdgeSharpness(hardEdge3) )
232
// printf("h = %f\n", h);
240
// Vertex point is...
242
// --- + ---- + --------
245
// Q = Average of face points surrounding old vertex
246
// R = average of midpoints of edges surrounding old vertex
248
// n = number of edges sharing the old vertex.
252
// Get the face points of the surrounding faces
253
std::vector<CqLath*> aQvf;
254
pVertex->Qvf( aQvf );
255
std::vector<CqLath*>::iterator iF;
256
for( iF = aQvf.begin(); iF != aQvf.end(); iF++ )
258
std::vector<CqLath*> aQfv;
260
std::vector<CqLath*>::iterator iV;
261
TypeA Val = TypeA(0.0f);
262
for( iV = aQfv.begin(); iV != aQfv.end(); iV++ )
263
Val += pParam->pValue( ((*iV)->*IndexFunction)() )[arrayindex];
264
Val = static_cast<TypeA>( Val / static_cast<TqFloat>( aQfv.size() ) );
270
// Get the midpoints of the surrounding edges
271
TypeA A = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
272
TypeA B = TypeA(0.0f);
273
std::vector<CqLath*>::iterator iE;
274
for( iE = aQve.begin(); iE != aQve.end(); iE++ )
276
B = pParam->pValue( ((*iE)->ccf()->*IndexFunction)() )[arrayindex];
277
R += static_cast<TypeA>( (A+B)/2.0f );
279
R = static_cast<TypeA>( R * 2.0f );
283
// Get the current vertex;
284
S = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
285
S = static_cast<TypeA>( S * static_cast<TqFloat>(n-3) );
288
//pParam->pValue( iIndex )[0] = Q+R+S;
294
// Get the midpoints of the surrounding 2 hardest edges
295
R = pParam->pValue((hardEdge1->ccf()->*IndexFunction)() )[arrayindex];
296
R = R + pParam->pValue((hardEdge2->ccf()->*IndexFunction)() )[arrayindex];
298
// Get the current vertex;
299
S = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
300
semiSharpPos = static_cast<TypeA>( ( R + ( S * 6.0f ) ) / 8.0f );
303
sharpPos = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
305
// Blend the three values together weighted by the sharpness values.
307
float h2 = hardEdge2 != NULL ? EdgeSharpness(hardEdge2) : 0.0f;
308
float h3 = hardEdge3 != NULL ? EdgeSharpness(hardEdge3) : 0.0f;
309
Pos = static_cast<TypeA>( (1.0f - h2)*softPos );
310
Pos = static_cast<TypeA>( Pos + (h2 - h3)*semiSharpPos );
311
Pos = static_cast<TypeA>( Pos + h3*sharpPos );
312
pParam->pValue( iIndex )[arrayindex] = Pos;
318
// Get a pointer to the appropriate index accessor function on CqLath based on class.
319
TqInt (CqLath::*IndexFunction)() const;
320
if( pParam->Class() == class_varying )
321
IndexFunction = &CqLath::VertexIndex;
323
IndexFunction = &CqLath::FaceVertexIndex;
325
TypeA A = pParam->pValue( (pVertex->*IndexFunction)() )[arrayindex];
326
pParam->pValue( iIndex )[arrayindex] = A;
330
void AddEdgeVertex(CqLath* pEdge, TqInt& iVIndex, TqInt& iFVIndex);
331
template<class TypeA, class TypeB>
332
void CreateEdgeVertex(CqParameterTyped<TypeA, TypeB>* pParam, CqLath* pEdge, TqInt iIndex)
334
TqInt arraysize = 0, arrayindex;
335
arraysize = pParam->Count();
336
for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
338
TypeA A = TypeA(0.0f);
339
TypeA B = TypeA(0.0f);
340
TypeA C = TypeA(0.0f);
342
if(pParam->Class() == class_vertex /*|| pParam->Class() == class_facevarying*/)
344
// Get a pointer to the appropriate index accessor function on CqLath based on class.
345
TqInt (CqLath::*IndexFunction)() const;
346
if( pParam->Class() == class_vertex )
347
IndexFunction = &CqLath::VertexIndex;
349
IndexFunction = &CqLath::FaceVertexIndex;
351
if( NULL != pEdge->ec() )
353
// Edge point is the average of the centrepoint of the original edge and the
354
// average of the two new face points of the adjacent faces.
355
std::vector<CqLath*> aQef;
357
std::vector<CqLath*>::iterator iF;
358
for( iF = aQef.begin(); iF != aQef.end(); iF++ )
360
std::vector<CqLath*> aQfv;
362
std::vector<CqLath*>::iterator iV;
363
TypeA Val = TypeA(0.0f);
364
for( iV = aQfv.begin(); iV != aQfv.end(); iV++ )
365
Val += pParam->pValue( ((*iV)->*IndexFunction)() )[arrayindex];
366
Val = static_cast<TypeA>( Val / static_cast<TqFloat>( aQfv.size() ) );
369
C = static_cast<TypeA>( C / static_cast<TqFloat>(aQef.size()) );
371
A = pParam->pValue( (pEdge->*IndexFunction)() )[arrayindex];
372
B = pParam->pValue( (pEdge->ccf()->*IndexFunction)() )[arrayindex];
374
float h = EdgeSharpness( pEdge );
375
A = static_cast<TypeA>( ((1.0f+h)*(A+B)) / 2.0f );
376
A = static_cast<TypeA>( (A + (1.0f-h)*C) / 2.0f );
380
A = pParam->pValue( (pEdge->*IndexFunction)() )[arrayindex];
381
B = pParam->pValue( (pEdge->ccf()->*IndexFunction)() )[arrayindex];
382
A = static_cast<TypeA>( (A+B)/2.0f );
387
// Get a pointer to the appropriate index accessor function on CqLath based on class.
388
TqInt (CqLath::*IndexFunction)() const;
389
if( pParam->Class() == class_varying )
390
IndexFunction = &CqLath::VertexIndex;
392
IndexFunction = &CqLath::FaceVertexIndex;
394
A = pParam->pValue( (pEdge->*IndexFunction)() )[arrayindex];
395
B = pParam->pValue( (pEdge->ccf()->*IndexFunction)() )[arrayindex];
396
A = static_cast<TypeA>( (A+B)/2.0f );
398
pParam->pValue( iIndex )[arrayindex] = A;
401
void AddFaceVertex(CqLath* pFace, TqInt& iVIndex, TqInt& iFVIndex);
402
template<class TypeA, class TypeB>
403
void CreateFaceVertex(CqParameterTyped<TypeA, TypeB>* pParam, CqLath* pFace, TqInt iIndex)
405
// Get a pointer to the appropriate index accessor function on CqLath based on class.
406
TqInt (CqLath::*IndexFunction)() const;
407
if( pParam->Class() == class_vertex || pParam->Class() == class_varying)
408
IndexFunction = &CqLath::VertexIndex;
410
IndexFunction = &CqLath::FaceVertexIndex;
411
// Face point is just the average of the original faces vertices.
412
std::vector<CqLath*> aQfv;
414
TqInt arraysize = 0, arrayindex;
415
arraysize = pParam->Count();
416
for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
418
std::vector<CqLath*>::iterator iV;
419
TypeA Val = TypeA(0.0f);
420
for( iV = aQfv.begin(); iV != aQfv.end(); iV++ )
422
assert( ((*iV)->*IndexFunction)() >= 0 &&
423
((*iV)->*IndexFunction)() < pParam->Size() );
424
Val += pParam->pValue( ((*iV)->*IndexFunction)() )[arrayindex];
426
Val = static_cast<TypeA>( Val / static_cast<TqFloat>( aQfv.size() ) );
427
pParam->pValue( iIndex )[arrayindex] = Val;
431
// Overrides from CqMotionSpec
432
virtual void ClearMotionObject( boost::shared_ptr<CqPolygonPoints>& A ) const
435
virtual boost::shared_ptr<CqPolygonPoints> ConcatMotionObjects( boost::shared_ptr<CqPolygonPoints> const & A, boost::shared_ptr<CqPolygonPoints> const & B ) const
439
virtual boost::shared_ptr<CqPolygonPoints> LinearInterpolateMotionObjects( TqFloat Fraction, boost::shared_ptr<CqPolygonPoints> const & A, boost::shared_ptr<CqPolygonPoints> const & B ) const
445
void OutputMesh(const char* fname, std::vector<CqLath*>* paFaces = 0);
446
void OutputInfo(const char* fname, std::vector<CqLath*>* paFaces = 0);
448
/// Declared private to prevent copying.
449
CqSubdivision2(const CqSubdivision2&);
450
/// Declared private to prevent copying.
451
CqSubdivision2& operator=(const CqSubdivision2&);
453
/// Array of pointers to laths, one each representing each facet.
454
std::vector<CqLath*> m_apFacets;
455
/// Array of arrays of pointers to laths each array representing the total laths referencing a single vertex.
456
std::vector<std::vector<CqLath*> > m_aapVertices;
457
/// Array of lath pointers, one for each lath generated.
458
std::vector<CqLath*> m_apLaths;
459
/// Map of face indices which are to be treated as holes in the surface, i.e. not rendered.
460
std::map<TqInt, TqBool> m_mapHoles;
461
/// Flag indicating whether this surface interpolates it's boundaries or not.
462
TqBool m_bInterpolateBoundary;
463
/// Map of sharp edges.
464
std::map<CqLath*, TqFloat> m_mapSharpEdges;
465
/// Map of sharp corners.
466
std::map<CqLath*, TqFloat> m_mapSharpCorners;
469
/// Flag indicating whether the topology structures have been finalised.
475
class CqSurfaceSubdivisionPatch : public CqBasicSurface
478
CqSurfaceSubdivisionPatch( const boost::shared_ptr<CqSubdivision2>& pTopology, CqLath* pFace)
480
m_pTopology = pTopology;
484
virtual ~CqSurfaceSubdivisionPatch()
490
CqString className() const { return CqString("CqSurfaceSubdivisionPatch"); }
493
/** Get the pointer to the subdivision surface hull that this patch is part of.
495
boost::shared_ptr<CqSubdivision2> pTopology() const
497
return( m_pTopology );
500
/** Get the index of the face on the hull that this patch refers to.
502
CqLath* pFace() const
507
virtual IqAttributes* pAttributes() const
509
return ( pTopology()->pPoints()->pAttributes() );
511
virtual IqTransform* pTransform() const
513
return ( pTopology()->pPoints()->pTransform() );
515
// Required implementations from IqSurface
516
virtual void Transform( const CqMatrix& matTx, const CqMatrix& matITTx, const CqMatrix& matRTx, TqInt iTime = 0 )
518
//pTopology()->pPoints( iTime )->Transform( matTx, matITTx, matRTx );
520
// NOTE: These should never be called.
521
virtual TqUint cUniform() const
525
virtual TqUint cVarying() const
529
virtual TqUint cVertex() const
533
virtual TqUint cFaceVarying() const
538
// Implementations required by CqBasicSurface
539
virtual CqBound Bound() const;
540
virtual CqMicroPolyGridBase* Dice();
541
virtual TqInt Split( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits );
542
virtual TqBool Diceable();
544
virtual CqMicroPolyGridBase* DiceExtract();
546
/** Determine whether the passed surface is valid to be used as a
547
* frame in motion blur for this surface.
549
virtual TqBool IsMotionBlurMatch( CqBasicSurface* pSurf )
554
void StoreDice( CqMicroPolyGrid* pGrid, const boost::shared_ptr<CqPolygonPoints>& pPoints, TqInt iParam, TqInt iFVParam, TqInt iVData);
555
boost::shared_ptr<CqSubdivision2> Extract( TqInt iTime );
558
boost::shared_ptr<CqSubdivision2> m_pTopology;
562
//----------------------------------------------------------------------
563
/** \class CqSurfacePointsPolygons
564
* Container surface to store the polygons making up a RiPointsPolygons surface.
567
class CqSurfaceSubdivisionMesh : public CqSurface
570
CqSurfaceSubdivisionMesh(const boost::shared_ptr<CqSubdivision2>& pTopology, TqInt NumFaces) :
571
m_NumFaces(NumFaces),
572
m_pTopology( pTopology )
575
virtual ~CqSurfaceSubdivisionMesh()
580
CqString className() const { return CqString("CqSurfaceSubdivisionMesh"); }
583
/** Get the gemoetric bound of this GPrim.
585
virtual CqBound Bound() const;
587
* \return A pointer to a new micropolygrid..
589
virtual CqMicroPolyGridBase* Dice()
593
/** Split this GPrim into a number of other GPrims.
594
* \param aSplits A reference to a CqBasicSurface array to fill in with the new GPrim pointers.
595
* \return Integer count of new GPrims created.
597
virtual TqInt Split( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits );
598
/** Determine whether this GPrim is diceable at its current size.
600
virtual TqBool Diceable()
605
virtual void Transform( const CqMatrix& matTx, const CqMatrix& matITTx, const CqMatrix& matRTx, TqInt iTime = 0 )
607
assert( m_pTopology );
608
m_pTopology->pPoints()->Transform( matTx, matITTx, matRTx, iTime );
611
virtual TqBool IsMotionBlurMatch( CqBasicSurface* pSurf )
616
virtual TqUint cUniform() const
618
return ( m_NumFaces );
620
virtual TqUint cVarying() const
622
assert( m_pTopology );
623
assert( m_pTopology->pPoints() );
624
return ( m_pTopology->pPoints()->cVarying() );
626
virtual TqUint cVertex() const
628
assert( m_pTopology );
629
assert( m_pTopology->pPoints() );
630
return ( m_pTopology->pPoints()->cVarying() );
632
virtual TqUint cFaceVarying() const
634
assert( m_pTopology );
635
assert( m_pTopology->pPoints() );
636
return ( m_pTopology->pPoints()->cFaceVarying() );
641
boost::shared_ptr<CqSubdivision2> m_pTopology; ///< Pointer to the associated CqPolygonPoints class.
645
END_NAMESPACE( Aqsis )
647
#endif // SUBDIVISION2_H_LOADED