OpenGL Catmull-Clark Subdivision: Interactive Subdivision and Limit Position Calculation
OpenGL Catmull-Clark Subdivision: Interactive Subdivision and Limit Position Calculation
This C++ program uses OpenGL to demonstrate Catmull-Clark subdivision. It allows users to interactively input the subdivision level ('x') and visualize the resulting subdivided mesh. The program also calculates and displays the limit positions of the vertices after 'x' subdivisions.
#include <GL/glut.h>
#include <iostream>
#include <vector>
#include <cmath>
// Define a mesh model data structure containing vertices and faces
struct MeshModel {
std::vector<GLfloat> vertices;
std::vector<GLint> faces;
};
// Initialize the mesh model
MeshModel initModel() {
MeshModel model;
model.vertices = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
model.faces = {
0, 1, 2, 3
};
return model;
}
// Draw the mesh model
void drawModel(const MeshModel& model) {
glBegin(GL_QUADS);
for (int i = 0; i < model.faces.size(); i += 4) {
for (int j = 0; j < 4; j++) {
int index = model.faces[i + j];
glVertex3f(model.vertices[index * 3], model.vertices[index * 3 + 1], model.vertices[index * 3 + 2]);
}
}
glEnd();
}
// Calculate the limit positions of the vertices
std::vector<GLfloat> calculateLimitPositions(const MeshModel& model, int division) {
std::vector<GLfloat> limitPositions = model.vertices;
for (int d = 0; d < division; d++) {
std::vector<GLfloat> newPositions;
std::vector<GLfloat> facePositions;
std::vector<int> vertexFaceCounts(model.vertices.size() / 3, 0);
// Calculate face center positions
for (int i = 0; i < model.faces.size(); i += 4) {
GLfloat faceX = 0.0f, faceY = 0.0f, faceZ = 0.0f;
for (int j = 0; j < 4; j++) {
int index = model.faces[i + j];
faceX += limitPositions[index * 3];
faceY += limitPositions[index * 3 + 1];
faceZ += limitPositions[index * 3 + 2];
vertexFaceCounts[index]++;
}
faceX /= 4.0f;
faceY /= 4.0f;
faceZ /= 4.0f;
facePositions.push_back(faceX);
facePositions.push_back(faceY);
facePositions.push_back(faceZ);
}
// Calculate vertex positions
for (int i = 0; i < model.vertices.size(); i += 3) {
GLfloat vertexX = 0.0f, vertexY = 0.0f, vertexZ = 0.0f;
int count = vertexFaceCounts[i / 3];
vertexX += (count - 2) * limitPositions[i];
vertexY += (count - 2) * limitPositions[i + 1];
vertexZ += (count - 2) * limitPositions[i + 2];
for (int j = 0; j < model.faces.size(); j += 4) {
for (int k = 0; k < 4; k++) {
int index = model.faces[j + k];
if (index == i / 3) {
vertexX += facePositions[j];
vertexY += facePositions[j + 1];
vertexZ += facePositions[j + 2];
}
}
}
vertexX /= count;
vertexY /= count;
vertexZ /= count;
newPositions.push_back(vertexX);
newPositions.push_back(vertexY);
newPositions.push_back(vertexZ);
}
limitPositions = newPositions;
}
return limitPositions;
}
// Rendering function
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
MeshModel model = initModel();
int division = 0;
std::cout << "请输入细分次数:";
std::cin >> division;
std::vector<GLfloat> limitPositions = calculateLimitPositions(model, division);
glColor3f(1.0f, 1.0f, 1.0f);
drawModel(model);
glColor3f(1.0f, 0.0f, 0.0f);
glTranslatef(1.0f, 0.0f, 0.0f);
drawModel({ limitPositions, model.faces });
glFlush();
}
// Window resize callback function
void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("Catmull-Clark Subdivision");
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
Note:
- To compile this program, you'll need to have OpenGL and GLUT libraries installed. Change the file extension to '.cpp' and link against these libraries during compilation.
- The program initially creates a simple quadrilateral mesh and displays both the original and subdivided mesh side-by-side for comparison.
- The program provides clear instructions to the user on how to input the subdivision level.
- The program is designed to be easily understood and modified for experimenting with different mesh models and subdivision levels.
- The
calculateLimitPositionsfunction efficiently computes the limit positions of the vertices after a given number of subdivisions. This is a fundamental concept in subdivision surface theory and is used to determine the final shape of the surface after infinite subdivisions.
原文地址: https://www.cveoy.top/t/topic/o8E4 著作权归作者所有。请勿转载和采集!