Skip to content

Commit 069ba54

Browse files
committed
loop now supports mixed n-gon meshes
1 parent c81de91 commit 069ba54

File tree

3 files changed

+27
-132
lines changed

3 files changed

+27
-132
lines changed

Model-Modifier/src/main.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -433,21 +433,10 @@ int main()
433433
objectVB.AssignData(mesh.m_OutVertices, mesh.m_OutNumVert * sizeof(float), DRAW_MODE::STATIC);
434434
objectIB.AssignData(mesh.m_OutIndices, mesh.m_OutNumIdx, DRAW_MODE::STATIC);
435435
}
436-
if (ImGui::Button("Loop Subdivision Surface (tri)"))
436+
if (ImGui::Button("Loop Subdivision Surface"))
437437
{
438438
Surface Lo(obj);
439-
obj = Lo.Loop3();
440-
mesh.Rebuild(obj); // rebuild mesh based on object info
441-
numFaces = static_cast<int>(mesh.m_Object.m_FaceIndices.size()); // update number of faces
442-
443-
objectVA.Bind();
444-
objectVB.AssignData(mesh.m_OutVertices, mesh.m_OutNumVert * sizeof(float), DRAW_MODE::STATIC);
445-
objectIB.AssignData(mesh.m_OutIndices, mesh.m_OutNumIdx, DRAW_MODE::STATIC);
446-
}
447-
if (ImGui::Button("Loop Subdivision Surface (quad)"))
448-
{
449-
Surface Lo(obj);
450-
obj = Lo.Loop4();
439+
obj = Lo.Loop();
451440
mesh.Rebuild(obj); // rebuild mesh based on object info
452441
numFaces = static_cast<int>(mesh.m_Object.m_FaceIndices.size()); // update number of faces
453442

Model-Modifier/src/scene/surface/Surface.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,15 @@ class Surface
5959
std::unordered_map<unsigned int, std::vector<glm::vec3>> pointsPerVertex,
6060
std::unordered_map<unsigned int, std::vector<glm::vec3>> pointsPerEdge
6161
);
62-
Object LoOutputOBJ3(std::vector<glm::vec3> edgePoints);
63-
Object LoOutputOBJ4(std::vector<glm::vec3> edgePoints);
62+
Object LoOutputOBJ(std::vector<glm::vec3> edgePoints);
6463
glm::mat4 ComputeQuadric(VertexRecord v0);
6564

6665
// Modification algorithms
6766
Object Beehive();
6867
Object Snowflake();
6968
Object CatmullClark();
7069
Object DooSabin();
71-
Object Loop3();
72-
Object Loop4();
70+
Object Loop();
7371
Object QEM();
7472

7573
public:

Model-Modifier/src/scene/surface/Surface_Loop.cpp

Lines changed: 23 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
////////// helpers to build the Object //////////
55

6-
Object Surface::LoOutputOBJ3(std::vector<glm::vec3> edgePoints)
6+
Object Surface::LoOutputOBJ(std::vector<glm::vec3> edgePoints)
77
{
88
// build new Object class (Loop style)
99
std::vector<glm::vec3> VertexPos;
@@ -13,76 +13,28 @@ Object Surface::LoOutputOBJ3(std::vector<glm::vec3> edgePoints)
1313

1414
for (FaceRecord face : m_Faces)
1515
{
16-
glm::vec3 vertA = m_Vertices[face.verticesIdx[0]].position;
17-
glm::vec3 vertB = m_Vertices[face.verticesIdx[1]].position;
18-
glm::vec3 vertC = m_Vertices[face.verticesIdx[2]].position;
16+
int n = static_cast<int>(face.verticesIdx.size());
1917

20-
glm::vec3 edgeAB = edgePoints[getEdgeIndex({ face.verticesIdx[0], face.verticesIdx[1] })];
21-
glm::vec3 edgeBC = edgePoints[getEdgeIndex({ face.verticesIdx[1], face.verticesIdx[2] })];
22-
glm::vec3 edgeCA = edgePoints[getEdgeIndex({ face.verticesIdx[2], face.verticesIdx[0] })];
23-
24-
// use vertex lookup to avoid creating duplicate vertices
25-
unsigned int vertAIdx = getVertIndex(vertA, VertexPos, VertLookup);
26-
unsigned int vertBIdx = getVertIndex(vertB, VertexPos, VertLookup);
27-
unsigned int vertCIdx = getVertIndex(vertC, VertexPos, VertLookup);
28-
unsigned int edgeABIdx = getVertIndex(edgeAB, VertexPos, VertLookup);
29-
unsigned int edgeBCIdx = getVertIndex(edgeBC, VertexPos, VertLookup);
30-
unsigned int edgeCAIdx = getVertIndex(edgeCA, VertexPos, VertLookup);
31-
32-
// create new faces (each original traingle will have 4 new triangles)
33-
FaceIndices.push_back({ vertAIdx, edgeABIdx, edgeCAIdx });
34-
FaceIndices.push_back({ edgeABIdx, vertBIdx, edgeBCIdx });
35-
FaceIndices.push_back({ edgeCAIdx, edgeBCIdx, vertCIdx });
36-
FaceIndices.push_back({ edgeCAIdx, edgeABIdx, edgeBCIdx });
37-
NumberPolygons[3] += 4;
38-
}
39-
40-
// build object
41-
Object Obj;
42-
Obj.m_Min = m_Min; Obj.m_Max = m_Max;
43-
Obj.m_VertexPos = VertexPos; Obj.m_FaceIndices = FaceIndices; Obj.m_TriFaceIndices = FaceIndices;
44-
Obj.m_NumPolygons = NumberPolygons;
45-
46-
return Obj;
47-
}
48-
49-
Object Surface::LoOutputOBJ4(std::vector<glm::vec3> edgePoints)
50-
{
51-
// build new Object class (Loop style)
52-
std::vector<glm::vec3> VertexPos;
53-
std::unordered_map<float, std::unordered_map<float, std::unordered_map<float, unsigned int>>> VertLookup;
54-
std::vector<std::vector<unsigned int>> FaceIndices;
55-
std::unordered_map<int, int> NumberPolygons;
56-
57-
for (FaceRecord face : m_Faces)
58-
{
59-
glm::vec3 vertA = m_Vertices[face.verticesIdx[0]].position;
60-
glm::vec3 vertB = m_Vertices[face.verticesIdx[1]].position;
61-
glm::vec3 vertC = m_Vertices[face.verticesIdx[2]].position;
62-
glm::vec3 vertD = m_Vertices[face.verticesIdx[3]].position;
18+
std::vector<unsigned int> vertsIdx;
19+
std::vector<unsigned int> edgesIdx;
20+
for (int i = 0; i < n; i++)
21+
{
22+
glm::vec3 vert = m_Vertices[face.verticesIdx[i]].position;
23+
vertsIdx.push_back(getVertIndex(vert, VertexPos, VertLookup));
6324

64-
glm::vec3 edgeAB = edgePoints[getEdgeIndex({ face.verticesIdx[0], face.verticesIdx[1] })];
65-
glm::vec3 edgeBC = edgePoints[getEdgeIndex({ face.verticesIdx[1], face.verticesIdx[2] })];
66-
glm::vec3 edgeCD = edgePoints[getEdgeIndex({ face.verticesIdx[2], face.verticesIdx[3] })];
67-
glm::vec3 edgeDA = edgePoints[getEdgeIndex({ face.verticesIdx[3], face.verticesIdx[0] })];
25+
glm::vec3 edge = edgePoints[getEdgeIndex({ face.verticesIdx[i], face.verticesIdx[(i + 1) % n] })];
26+
edgesIdx.push_back(getVertIndex(edge, VertexPos, VertLookup));
27+
}
6828

69-
// use vertex lookup to avoid creating duplicate vertices
70-
unsigned int vertAIdx = getVertIndex(vertA, VertexPos, VertLookup);
71-
unsigned int vertBIdx = getVertIndex(vertB, VertexPos, VertLookup);
72-
unsigned int vertCIdx = getVertIndex(vertC, VertexPos, VertLookup);
73-
unsigned int vertDIdx = getVertIndex(vertD, VertexPos, VertLookup);
74-
unsigned int edgeABIdx = getVertIndex(edgeAB, VertexPos, VertLookup);
75-
unsigned int edgeBCIdx = getVertIndex(edgeBC, VertexPos, VertLookup);
76-
unsigned int edgeCDIdx = getVertIndex(edgeCD, VertexPos, VertLookup);
77-
unsigned int edgeDAIdx = getVertIndex(edgeDA, VertexPos, VertLookup);
78-
unsigned int FaceIdx = getVertIndex(face.facePoint, VertexPos, VertLookup);
29+
// every n-gon gets one n-gon inscribed inside, and gets n more triangles
30+
FaceIndices.push_back(edgesIdx);
31+
for (int i = 0; i < n; i++)
32+
{
33+
FaceIndices.push_back({ vertsIdx[i], edgesIdx[i], edgesIdx[(i + n - 1) % n] });
34+
}
7935

80-
// create new faces (each original quad will have 4 new quads)
81-
FaceIndices.push_back({ vertAIdx, edgeABIdx, FaceIdx, edgeDAIdx });
82-
FaceIndices.push_back({ vertBIdx, edgeBCIdx, FaceIdx, edgeABIdx });
83-
FaceIndices.push_back({ vertCIdx, edgeCDIdx, FaceIdx, edgeBCIdx });
84-
FaceIndices.push_back({ vertDIdx, edgeDAIdx, FaceIdx, edgeCDIdx });
85-
NumberPolygons[4] += 4;
36+
NumberPolygons[n] += 1;
37+
NumberPolygons[3] += n;
8638
}
8739

8840
// build object
@@ -91,13 +43,15 @@ Object Surface::LoOutputOBJ4(std::vector<glm::vec3> edgePoints)
9143
Obj.m_VertexPos = VertexPos; Obj.m_FaceIndices = FaceIndices;
9244
Obj.m_NumPolygons = NumberPolygons;
9345
Obj.TriangulateFaces();
46+
9447
return Obj;
9548
}
9649

50+
9751
////////// algorithms //////////
9852

9953
// Loop subdivision surface algorithm
100-
Object Surface::Loop3()
54+
Object Surface::Loop()
10155
{
10256
// make new (odd) vertices (per edge)
10357
std::vector<glm::vec3> edgePoints(m_Edges.size());
@@ -139,51 +93,5 @@ Object Surface::Loop3()
13993
}
14094
}
14195

142-
return LoOutputOBJ3(edgePoints);
143-
}
144-
145-
// Loop subdivision surface algorithm
146-
Object Surface::Loop4()
147-
{
148-
// make new (odd) vertices (per edge)
149-
std::vector<glm::vec3> edgePoints(m_Edges.size());
150-
for (int i = 0; i < edgePoints.size(); i++)
151-
{
152-
EdgeRecord currEdge = m_Edges[i];
153-
if (currEdge.adjFacesIdx.size() == 1) // boundary edge
154-
{
155-
// ME point
156-
edgePoints[i] = currEdge.midEdgePoint;
157-
}
158-
else // edge borders 2 faces
159-
{
160-
// 3/8 face points + 2/8 edge point
161-
edgePoints[i] = 0.375f * m_Faces[currEdge.adjFacesIdx[0]].facePoint +
162-
0.375f * m_Faces[currEdge.adjFacesIdx[1]].facePoint +
163-
0.25f * currEdge.midEdgePoint;
164-
}
165-
}
166-
167-
// update old (even) vertices (per vertex)
168-
for (int i = 0; i < m_Vertices.size(); i++)
169-
{
170-
VertexRecord vert = m_Vertices[i];
171-
glm::vec3 vertPos = vert.position;
172-
float alpha = 0.2f;
173-
glm::vec3 sumNeighbours{ 0 };
174-
for (unsigned int adjEdge : vert.adjEdgesIdx)
175-
{
176-
sumNeighbours += 2.0f * m_Edges[adjEdge].midEdgePoint - vertPos;
177-
}
178-
int neighbours = static_cast<int>(vert.adjEdgesIdx.size());
179-
if (neighbours == 3)
180-
m_Vertices[i].position = 0.25f * vertPos + 0.125f * sumNeighbours;
181-
else
182-
{
183-
float invNeigh = 1 / (float)neighbours;
184-
m_Vertices[i].position = (1 - alpha) * sumNeighbours * invNeigh + alpha * vertPos;
185-
}
186-
}
187-
188-
return LoOutputOBJ4(edgePoints);
96+
return LoOutputOBJ(edgePoints);
18997
}

0 commit comments

Comments
 (0)