C++ OpenGL 实现双三次 B-样条曲面片绘制
以下是一个简单的双三次 B-样条曲面片的 C++ 代码示例,使用 OpenGL 库进行绘制。
#include <GL/glut.h>
const int MAX_POINTS = 20; // 最大控制点数
const int ORDER = 4; // 阶数
int numPoints = 0; // 当前控制点数
GLfloat controlPoints[MAX_POINTS][MAX_POINTS][3]; // 控制点数组
void init() {
glClearColor(1.0, 1.0, 1.0, 1.0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
gluPerspective(45.0, 1.0, 1.0, 100.0);
}
// 计算 B-样条基函数
GLfloat BSplineBasis(int i, int k, GLfloat u, GLfloat* knots) {
if (k == 0) {
if (u >= knots[i] && u < knots[i + 1]) {
return 1.0;
}
return 0.0;
}
GLfloat w1 = 0.0, w2 = 0.0;
if (knots[i + k] - knots[i] > 0.0) {
w1 = ((u - knots[i]) / (knots[i + k] - knots[i])) * BSplineBasis(i, k - 1, u, knots);
}
if (knots[i + k + 1] - knots[i + 1] > 0.0) {
w2 = ((knots[i + k + 1] - u) / (knots[i + k + 1] - knots[i + 1])) * BSplineBasis(i + 1, k - 1, u, knots);
}
return w1 + w2;
}
// 计算双三次 B-样条曲面片上某个点的坐标
void calculateBSplinePoint(GLfloat u, GLfloat v, GLfloat* point) {
GLfloat uKnots[MAX_POINTS + ORDER] = {0.0, 0.0, 0.0, 0.0};
GLfloat vKnots[MAX_POINTS + ORDER] = {0.0, 0.0, 0.0, 0.0};
for (int i = 0; i < numPoints + ORDER; i++) {
if (i >= ORDER && i < numPoints + ORDER) {
uKnots[i] = (GLfloat)i / (numPoints + ORDER - 1);
vKnots[i] = (GLfloat)i / (numPoints + ORDER - 1);
}
}
GLfloat uBasis[ORDER], vBasis[ORDER];
GLfloat x = 0.0, y = 0.0, z = 0.0;
for (int i = 0; i < numPoints; i++) {
for (int j = 0; j < numPoints; j++) {
uBasis[0] = BSplineBasis(i, ORDER - 1, u, uKnots);
vBasis[0] = BSplineBasis(j, ORDER - 1, v, vKnots);
for (int k = 1; k < ORDER; k++) {
uBasis[k] = BSplineBasis(i, ORDER - k - 1, u, uKnots);
vBasis[k] = BSplineBasis(j, ORDER - k - 1, v, vKnots);
}
x += controlPoints[i][j][0] * uBasis[ORDER - 1] * vBasis[ORDER - 1];
y += controlPoints[i][j][1] * uBasis[ORDER - 1] * vBasis[ORDER - 1];
z += controlPoints[i][j][2] * uBasis[ORDER - 1] * vBasis[ORDER - 1];
}
}
point[0] = x;
point[1] = y;
point[2] = z;
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
GLfloat point[3];
for (GLfloat u = 0.0; u < 1.0; u += 0.1) {
glBegin(GL_LINE_STRIP);
for (GLfloat v = 0.0; v < 1.0; v += 0.1) {
calculateBSplinePoint(u, v, point);
glVertex3fv(point);
}
glEnd();
}
for (GLfloat v = 0.0; v < 1.0; v += 0.1) {
glBegin(GL_LINE_STRIP);
for (GLfloat u = 0.0; u < 1.0; u += 0.1) {
calculateBSplinePoint(u, v, point);
glVertex3fv(point);
}
glEnd();
}
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y) {
switch(key) {
case 27:
exit(0);
break;
}
}
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
GLfloat winX = (GLfloat)x;
GLfloat winY = (GLfloat)glutGet(GLUT_WINDOW_HEIGHT) - (GLfloat)y;
GLfloat winZ = 0.0;
GLfloat posX = 0.0, posY = 0.0, posZ = 0.0;
glReadPixels(x, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
gluUnProject(winX, winY, winZ,
(GLfloat*)glutGet(GLUT_WINDOW_MODELVIEW_MATRIX),
(GLfloat*)glutGet(GLUT_WINDOW_PROJECTION_MATRIX),
(GLint*)glutGet(GLUT_WINDOW_VIEWPORT),
&posX, &posY, &posZ);
if (numPoints < MAX_POINTS) {
controlPoints[numPoints][0] = posX;
controlPoints[numPoints][1] = posY;
controlPoints[numPoints][2] = posZ;
numPoints++;
}
}
glutPostRedisplay();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow('B-Spline Surface');
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
该代码使用双三次 B-样条曲面片算法,可以绘制曲面片并使用鼠标添加控制点。在 OpenGL 中使用 gluUnProject 函数将鼠标点击位置转换为三维坐标,然后将该坐标作为控制点添加到控制点数组中。在每次绘制时,使用 calculateBSplinePoint 函数计算出曲面片上每个点的坐标并绘制出来。
原文地址: https://www.cveoy.top/t/topic/lBHR 著作权归作者所有。请勿转载和采集!