一、实验目的
- 利用 d e − C a s t e l j a u {\rm de-Casteljau} de−Casteljau递推算法绘制3-4次 B e z i e r {\rm Bezier} Bezier曲面
二、实验环境
- Visual Studio 2019
- Windows 10
三、算法分析与设计
曲线
将 t t t从 0 0 0取至 1 1 1(指与线段总长之比),点 P P P的轨迹就形成了一条由端点加权赋得的曲线。
示意图如下:
也就是每次由
n
+
1
n+1
n+1个点推出
n
n
n个新点,最终得到目标点
P
P
P
P
0
,
P
1
,
P
2
,
P
3
⇒
Q
0
,
Q
1
,
Q
2
⇒
R
0
,
R
1
⇒
P
P_0,P_1,P_2,P_3\Rightarrow Q_0,Q_1,Q_2\Rightarrow R_0,R_1\Rightarrow P
P0,P1,P2,P3⇒Q0,Q1,Q2⇒R0,R1⇒P
曲面
将曲面视为由相互正交的线组成的网格,于是求曲面的过程可以转化为求组成网格的各曲线。
- 对每一列的 n + 1 n+1 n+1个点确定一条曲线
- 对每一行的 n + 1 n+1 n+1个点确定一条曲线
四、实验结果
三次 B e z i e r {\rm Bezier} Bezier曲面
四次 B e z i e r {\rm Bezier} Bezier曲面
五、附录
三次 B e z i e r {\rm Bezier} Bezier曲面
#include<GL/glew.h>
#include <GLFW/glfw3.h>
#include<bits/stdc++.h>
#define PI acos(-1)
#define MAXN 3600
#define M 1000
using namespace std;
GLfloat ctrlPoints[4][4][3] =
// ctrlPoints[i][j]:该点在网格的第i行第j列上
{
{
{ -0.8f, -0.7f, 0.2f }, { -0.3f, -0.6f, 0.2f }, { 0.2f, -0.65f, 0.3f }, { 0.7f, -0.7f, 0.2f }
},
{
{ -0.9f, -0.2f, 0.3f }, { -0.3f, 0.2f, 0.5f }, { 0.3f, -0.2f, 0.4f }, { 0.75f, -0.2f, 0.3f },
},
{
{ -0.9f, 0.3f, 0.3f }, { -0.3f, 0.2f, 0.5f }, { 0.25f, 0.25f, 0.6f }, { 0.8f, 0.3f, 0.3f },
},
{
{ -0.8f, 0.8f, 0.1f }, { -0.3f, 0.8f, 0.2f }, { 0.2f, 0.85f, 0.1f }, { 0.7f, 0.8f, 0.1f },
}
};
void plotPoint()
{
glPointSize(5.0);
glColor3f(1.0, 1.0, 0.0);
for (int i = 0; i < 4; i++)
{
glBegin(GL_POINTS);
for (int j = 0; j < 4; j++)
glVertex3fv(&ctrlPoints[i][j][0]);
glEnd();
}
glColor3f(0.0, 1.0, 1.0);
for (int i = 0; i < 4; i++) {
// 固定行标,画横线
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 4; j++)
glVertex3fv(&ctrlPoints[i][j][0]);
glEnd();
// 固定列标,画竖线
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 4; j++)
glVertex3fv(&ctrlPoints[j][i][0]);
glEnd();
}
}
void bezierSurface()
{
int n = 4; // 控制点的数目
float xarray[4];
float yarray[4];
float zarray[4];
GLfloat ps[11][4][3];
// 由4*4=16个点确定4*11=44个点,即对每列(共4列)的四个点确定一条曲线
for (int v = 0; v < 4; v++)
{
int u = 0;
for (double t = 0.0; t <= 1; t += 0.1)
{
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < n - i; ++j)
{
if (i == 1)
// 第一次,使用控制点
{
xarray[j] = ctrlPoints[j][v][0] * (1 - t) + ctrlPoints[j + 1][v][0] * t;
yarray[j] = ctrlPoints[j][v][1] * (1 - t) + ctrlPoints[j + 1][v][1] * t;
zarray[j] = ctrlPoints[j][v][2] * (1 - t) + ctrlPoints[j + 1][v][2] * t;
continue;
}
// 非第一次,更新点数组
xarray[j] = xarray[j] * (1 - t) + xarray[j + 1] * t;
yarray[j] = yarray[j] * (1 - t) + yarray[j + 1] * t;
zarray[j] = zarray[j] * (1 - t) + zarray[j + 1] * t;
}
}
ps[u][v][0] = xarray[0];
ps[u][v][1] = yarray[0];
ps[u][v][2] = zarray[0];
u++;
}
}
//glColor3f(255.0, 0.0, 0.0);
//for (int i = 0; i < 11; i++)
//{
// glBegin(GL_LINE_STRIP);
// for (int j = 0; j < 4; j++)
// glVertex3fv(&ps[i][j][0]);
// glEnd();
//}
GLfloat ps1[11][11][3];
// 由4*11=44个点确定11*11=121个点,即对每行(共11行)的四个点确定一条曲线
for (int v = 0; v < 11; v++) {
int u = 0;
for (double t = 0.0; t <= 1; t += 0.1)
{
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < n - i; ++j)
{
if (i == 1)
{
xarray[j] = ps[v][j][0] * (1 - t) + ps[v][j + 1][0] * t;
yarray[j] = ps[v][j][1] * (1 - t) + ps[v][j + 1][1] * t;
zarray[j] = ps[v][j][2] * (1 - t) + ps[v][j + 1][2] * t;
continue;
}
xarray[j] = xarray[j] * (1 - t) + xarray[j + 1] * t;
yarray[j] = yarray[j] * (1 - t) + yarray[j + 1] * t;
zarray[j] = zarray[j] * (1 - t) + zarray[j + 1] * t;
}
}
ps1[v][u][0] = xarray[0];
ps1[v][u][1] = yarray[0];
ps1[v][u][2] = zarray[0];
u++;
}
}
glColor3f(1.0, 1.0, 1.0);
for (int i = 0; i < 11; i++)
{
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 11; j++)
glVertex3fv(&ps1[i][j][0]);
glEnd();
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 11; j++)
glVertex3fv(&ps1[j][i][0]);
glEnd();
}
glFlush();
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(960, 960, "bezierSurface", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
glRotatef(300.0, 1.0, 0.0, 0.0);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
plotPoint();
bezierSurface();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
四次 B e z i e r {\rm Bezier} Bezier曲面
#include<GL/glew.h>
#include <GLFW/glfw3.h>
#include<bits/stdc++.h>
#define PI acos(-1)
#define MAXN 3600
#define M 1000
using namespace std;
GLfloat ctrlPoints[5][5][3] =
// ctrlPoints[i][j]:该点在网格的第i行第j列上
{
{
{ -0.8f, -0.7f, 0.2f }, { -0.3f, -0.6f, 0.2f }, {0.0f,-0.6f,0.2f}, { 0.2f, -0.65f, 0.3f }, { 0.7f, -0.7f, 0.2f }
},
{
{ -0.9f, -0.2f, 0.3f }, { -0.3f, 0.0f, 0.5f }, {0.1f,-0.2f,0.3f},{ 0.3f, -0.2f, 0.4f }, { 0.75f, -0.2f, 0.3f },
},
{
{ -0.8f, 0.0f, 0.4f }, { -0.3f, 0.0f, 0.2f }, {0.0f,-0.1f,0.4f},{ 0.2f, 0.0f, 0.5f }, { 0.7f, 0.0f, 0.1f },
},
{
{ -0.9f, 0.3f, 0.3f }, { -0.3f, 0.2f, 0.5f }, {0.0f,0.2f,0.6f},{ 0.25f, 0.25f, 0.6f }, { 0.8f, 0.3f, 0.3f },
},
{
{ -0.8f, 0.8f, 0.1f }, { -0.3f, 0.8f, 0.2f }, {0.1f,0.8f,0.1f},{ 0.2f, 0.85f, 0.1f }, { 0.7f, 0.8f, 0.1f },
},
};
void plotPoint()
{
glPointSize(5.0);
glColor3f(1.0, 1.0, 0.0);
for (int i = 0; i < 5; i++)
{
glBegin(GL_POINTS);
for (int j = 0; j < 5; j++)
glVertex3fv(&ctrlPoints[i][j][0]);
glEnd();
}
glColor3f(0.0, 1.0, 1.0);
for (int i = 0; i < 5; i++) {
// 固定行标,画横线
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 5; j++)
glVertex3fv(&ctrlPoints[i][j][0]);
glEnd();
// 固定列标,画竖线
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 5; j++)
glVertex3fv(&ctrlPoints[j][i][0]);
glEnd();
}
}
void bezierSurface()
{
int n = 5; // 控制点的数目
float xarray[5];
float yarray[5];
float zarray[5];
GLfloat ps[11][5][3];
for (int v = 0; v < 5; v++)
{
int u = 0;
for (double t = 0.0; t <= 1; t += 0.1)
{
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < n - i; ++j)
{
if (i == 1)
// 第一次,使用控制点
{
xarray[j] = ctrlPoints[j][v][0] * (1 - t) + ctrlPoints[j + 1][v][0] * t;
yarray[j] = ctrlPoints[j][v][1] * (1 - t) + ctrlPoints[j + 1][v][1] * t;
zarray[j] = ctrlPoints[j][v][2] * (1 - t) + ctrlPoints[j + 1][v][2] * t;
continue;
}
// 非第一次,更新点数组
xarray[j] = xarray[j] * (1 - t) + xarray[j + 1] * t;
yarray[j] = yarray[j] * (1 - t) + yarray[j + 1] * t;
zarray[j] = zarray[j] * (1 - t) + zarray[j + 1] * t;
}
}
ps[u][v][0] = xarray[0];
ps[u][v][1] = yarray[0];
ps[u][v][2] = zarray[0];
u++;
}
}
//glColor3f(255.0, 0.0, 0.0);
//for (int i = 0; i < 11; i++)
//{
// glBegin(GL_LINE_STRIP);
// for (int j = 0; j < 5; j++)
// glVertex3fv(&ps[i][j][0]);
// glEnd();
//}
GLfloat ps1[11][11][3];
for (int v = 0; v < 11; v++) {
int u = 0;
for (double t = 0.0; t <= 1; t += 0.1)
{
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < n - i; ++j)
{
if (i == 1)
{
xarray[j] = ps[v][j][0] * (1 - t) + ps[v][j + 1][0] * t;
yarray[j] = ps[v][j][1] * (1 - t) + ps[v][j + 1][1] * t;
zarray[j] = ps[v][j][2] * (1 - t) + ps[v][j + 1][2] * t;
continue;
}
xarray[j] = xarray[j] * (1 - t) + xarray[j + 1] * t;
yarray[j] = yarray[j] * (1 - t) + yarray[j + 1] * t;
zarray[j] = zarray[j] * (1 - t) + zarray[j + 1] * t;
}
}
ps1[v][u][0] = xarray[0];
ps1[v][u][1] = yarray[0];
ps1[v][u][2] = zarray[0];
u++;
}
}
glColor3f(1.0, 1.0, 1.0);
for (int i = 0; i < 11; i++)
{
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 11; j++)
glVertex3fv(&ps1[i][j][0]);
glEnd();
glBegin(GL_LINE_STRIP);
for (int j = 0; j < 11; j++)
glVertex3fv(&ps1[j][i][0]);
glEnd();
}
glFlush();
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(960, 960, "bezierSurface", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
glRotatef(300.0, 1.0, 0.0, 0.0);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
plotPoint();
bezierSurface();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}