Skip to content

Commit 390cd5b

Browse files
committed
Added correct code for Catmull Clark subdivision surfaces
1 parent 15de312 commit 390cd5b

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/****************************************************************************
2+
* VCGLib o o *
3+
* Visual and Computer Graphics Library o o *
4+
* _ O _ *
5+
* Copyright(C) 2004-2024 \/)\/ *
6+
* Visual Computing Lab /\/| *
7+
* ISTI - Italian National Research Council | *
8+
* \ *
9+
* All rights reserved. *
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
* This program is distributed in the hope that it will be useful, *
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19+
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20+
* for more details. *
21+
* *
22+
****************************************************************************/
23+
24+
#pragma once
25+
26+
namespace vcg {
27+
namespace tri {
28+
/// \ingroup trimesh
29+
30+
/// \headerfile refine_doosabin.h vcg/complex/algorithms/refine_doosabin.h
31+
32+
/// \brief This class is used convert between polygonal meshes and triangular meshes
33+
34+
/**
35+
This class contains two members that allow to build a triangular mesh from a polygonal mesh
36+
and viceversa. In a trimesh, the generic polygons with n sides are codified represented by
37+
tagging the internal edge of the face as 'faux' with the SetF.
38+
*/
39+
40+
template <class PolyMeshType>
41+
class CatmullClark {
42+
typedef typename PolyMeshType::FaceType FaceType;
43+
typedef typename PolyMeshType::FacePointer FacePointer;
44+
typedef typename PolyMeshType::FaceIterator FaceIterator;
45+
typedef typename PolyMeshType::VertexIterator VertexIterator;
46+
47+
public:
48+
static void Refine(PolyMeshType &baseIn, PolyMeshType &refinedOut, int iterationNum=1)
49+
{
50+
PolyMeshType baseTmp,outTmp;
51+
52+
tri::Append<PolyMeshType,PolyMeshType>::MeshCopy(baseTmp,baseIn);
53+
54+
for(int i=0;i<iterationNum;++i)
55+
{
56+
RefineSingleStep(baseTmp, outTmp);
57+
tri::Append<PolyMeshType,PolyMeshType>::MeshCopy(baseTmp,outTmp);
58+
}
59+
tri::Append<PolyMeshType,PolyMeshType>::MeshCopy(refinedOut,outTmp);
60+
}
61+
62+
63+
static void RefineSingleStep(PolyMeshType &baseIn, PolyMeshType &refinedOut)
64+
{
65+
tri::RequirePolygonalMesh(baseIn);
66+
tri::RequirePolygonalMesh(refinedOut);
67+
refinedOut.Clear();
68+
//tri::RequireFFAdjacency(baseIn);
69+
// for the output mesh we keep a counter for each vertex as an additional attribute to computing averages easily
70+
auto v_cnH = tri::Allocator<PolyMeshType>::template AddPerVertexAttribute<int>(refinedOut,"counter");
71+
72+
// for the input mesh we keep an attribute with the valence of the vertices
73+
auto v_valH = tri::Allocator<PolyMeshType>:: template AddPerVertexAttribute<int>(baseIn,"valence");
74+
75+
// step -1 init the vertex valence counter to zero
76+
for(auto &v : baseIn.vert)
77+
v_valH[&v]=0;
78+
79+
// Compute Valence for each vertex by iterating on all the faces
80+
for(auto &f : baseIn.face)
81+
for(int i=0;i<f.VN();i++)
82+
v_valH[f.V(i)]++;
83+
84+
// step 0 copy all the vertexes in the output mesh
85+
for(auto &v : baseIn.vert)
86+
tri::Allocator<PolyMeshType>::AddVertex(refinedOut,Point3f(0,0,0));
87+
printf( "Mesh has %i vert and %i faces\n", refinedOut.VN(), refinedOut.FN() );
88+
89+
// We keep two maps to store the new vertices created for the edges and the faces
90+
// and retrieve them when actually building the connectivity of the new mesh
91+
std::map<std::pair<int,int>, int> edgeMap;
92+
std::map<int, int> faceMap;
93+
94+
// First Step Create the mid face vertices
95+
for(auto &f : baseIn.face)
96+
{
97+
auto vp = tri::Allocator<PolyMeshType>::AddVertex(refinedOut,PolyBarycenter(f));
98+
faceMap[tri::Index(baseIn,f)] = tri::Index(refinedOut,*vp);
99+
}
100+
101+
// Second step. Create a vertex for each edge.
102+
// looping over all faces
103+
for(auto &f : baseIn.face)
104+
{
105+
Point3f center = refinedOut.vert[faceMap[tri::Index(baseIn,f)]].P();
106+
// loop over all edges
107+
for(int i=0;i<f.VN();i++)
108+
{
109+
int v0 = tri::Index(baseIn,f.V0(i));
110+
int v1 = tri::Index(baseIn,f.V1(i));
111+
if(v0>v1) std::swap(v0,v1);
112+
113+
// check if the edge is already in the map
114+
auto it = edgeMap.find(std::make_pair(v0,v1));
115+
116+
int edgeVertIndex;
117+
if(it == edgeMap.end())
118+
{
119+
// if not, create a new vertex in the middle of the edge
120+
auto vp = tri::Allocator<PolyMeshType>::AddVertex(refinedOut,Point3f(0,0,0));
121+
edgeMap[std::make_pair(v0,v1)] = tri::Index(refinedOut,*vp);
122+
edgeVertIndex = tri::Index(refinedOut,*vp);
123+
}
124+
else
125+
{
126+
edgeVertIndex = it->second;
127+
}
128+
129+
refinedOut.vert[edgeVertIndex].P() += center*0.5;
130+
refinedOut.vert[edgeVertIndex].P() += f.V0(i)->P()*0.25;
131+
refinedOut.vert[edgeVertIndex].P() += f.V1(i)->P()*0.25;
132+
133+
v_cnH[edgeVertIndex]+=1; // increment the counter of the vertex for the face
134+
}
135+
}
136+
// the only normalization step we do is for edge vertices to handle the fact
137+
// that on boundary faces we do not have two contributions so the weight should be doubled.
138+
for(auto &v : refinedOut.vert)
139+
if(v_cnH[v]>0) v.P() /= v_cnH[&v];
140+
141+
// Third step compute new the position of the original vertices
142+
for(auto &f : baseIn.face)
143+
{
144+
Point3f center = refinedOut.vert[faceMap[tri::Index(baseIn,f)]].P();
145+
146+
// for each vertex of the face we add to its position
147+
// the coords of the baricenter and of the two vertices adjacent to it
148+
for(int i=0;i<f.VN();i++)
149+
{
150+
float val = v_valH[f.V(i)];
151+
float val1 = (val -2.0)/(val*val);
152+
float val2 = 1.0/(val*val);
153+
154+
int v0 = tri::Index(baseIn,f.V0(i));
155+
int v1 = tri::Index(baseIn,f.V1(i));
156+
if(v0>v1) std::swap(v0,v1);
157+
Point3f edgep = refinedOut.vert[edgeMap[std::make_pair(v0,v1)]].P();
158+
159+
refinedOut.vert[tri::Index(baseIn,f.V(i))].P() += f.V(i)->P() * val1;
160+
refinedOut.vert[tri::Index(baseIn,f.V(i))].P() += center * val2;
161+
refinedOut.vert[tri::Index(baseIn,f.V(i))].P() += edgep * val2;
162+
}
163+
}
164+
165+
printf( "Mesh has %i vert and %i faces\n", refinedOut.VN(), refinedOut.FN() );
166+
167+
// Final step. Create Connectivity: a new face for each wedge of each face of the original mesh
168+
for(auto &f : baseIn.face)
169+
{
170+
// loop over all wedge of the face
171+
for(int i=0;i<f.VN();i++)
172+
{
173+
int e00 = tri::Index(baseIn,f.V0(i));
174+
int e01 = tri::Index(baseIn,f.V1(i));
175+
int e10 = tri::Index(baseIn,f.V0(i));
176+
int e11 = tri::Index(baseIn,f.V((i+f.VN()-1)%f.VN()));
177+
if(e00>e01) std::swap(e00,e01);
178+
if(e10>e11) std::swap(e10,e11);
179+
180+
// retrieve the edge vertices
181+
auto e1it = edgeMap.find(std::make_pair(e00,e01));
182+
auto e2it = edgeMap.find(std::make_pair(e10,e11));
183+
184+
// retrieve the face vertex
185+
auto fit = faceMap.find(tri::Index(baseIn,f));
186+
187+
auto v0p = &refinedOut.vert[tri::Index(baseIn,f.V(i))];
188+
auto v1p = &refinedOut.vert[e1it->second];
189+
auto v2p = &refinedOut.vert[fit->second];
190+
auto v3p = &refinedOut.vert[e2it->second];
191+
192+
tri::Allocator<PolyMeshType>::AddQuadFace(refinedOut, v0p, v1p, v2p, v3p);
193+
}
194+
}// fprintf(stdout,"Refining starting \n");fflush(stdout);
195+
tri::Allocator<PolyMeshType>::template DeletePerVertexAttribute<int>(refinedOut,v_cnH);
196+
197+
// for the input mesh we keep an attribute with the valence of the vertices
198+
tri::Allocator<PolyMeshType>:: template DeletePerVertexAttribute<int>(baseIn,v_valH);
199+
200+
} // end refine Function
201+
202+
}; // end CatmullClark class
203+
} // end namespace tri
204+
} // end namespace vcg
205+

0 commit comments

Comments
 (0)