Files
Computer-Graphics-Lab/lab4/lab4.cpp
T
2026-05-12 22:07:06 +08:00

119 lines
5.6 KiB
C++

#include <GL/glut.h> // 引入 GLUT 和 OpenGL 相关函数。
const int WINDOW_WIDTH = 800; // 设置窗口宽度。
const int WINDOW_HEIGHT = 600; // 设置窗口高度。
const int CURVE_SEGMENTS = 10000; // 设置曲线分段数量,数量越大曲线越平滑。
struct Vec2 { // 定义二维坐标点结构体。
double x; // 保存点的 x 坐标。
double y; // 保存点的 y 坐标。
};
Vec2 controlStart = { -300.0, -100.0 }; // Bezier 曲线的起点。
Vec2 controlHandleA = { 0.0, 200.0 }; // 第一个控制点,用来影响曲线起始方向。
Vec2 controlHandleB = { 200.0, 300.0 }; // 第二个控制点,用来影响曲线结束方向。
Vec2 controlEnd = { 300.0, 100.0 }; // Bezier 曲线的终点。
Vec2 calculateBezierPoint(double t) { // 根据参数 t 计算三次 Bezier 曲线上的点。
double inverseT = 1.0 - t; // 计算 1 - t,方便套用 Bezier 公式。
double startWeight = inverseT * inverseT * inverseT; // 起点对应的权重。
double handleAWeight = 3.0 * t * inverseT * inverseT; // 第一个控制点对应的权重。
double handleBWeight = 3.0 * t * t * inverseT; // 第二个控制点对应的权重。
double endWeight = t * t * t; // 终点对应的权重。
Vec2 curvePoint; // 保存当前计算出的曲线点。
curvePoint.x = startWeight * controlStart.x // 按权重累加起点的 x 坐标。
+ handleAWeight * controlHandleA.x // 按权重累加第一个控制点的 x 坐标。
+ handleBWeight * controlHandleB.x // 按权重累加第二个控制点的 x 坐标。
+ endWeight * controlEnd.x; // 按权重累加终点的 x 坐标。
curvePoint.y = startWeight * controlStart.y // 按权重累加起点的 y 坐标。
+ handleAWeight * controlHandleA.y // 按权重累加第一个控制点的 y 坐标。
+ handleBWeight * controlHandleB.y // 按权重累加第二个控制点的 y 坐标。
+ endWeight * controlEnd.y; // 按权重累加终点的 y 坐标。
return curvePoint; // 返回曲线上当前参数 t 对应的点。
}
void submitControlVertices() { // 将四个控制点提交给当前 OpenGL 绘制命令。
glVertex2d(controlStart.x, controlStart.y); // 提交起点坐标。
glVertex2d(controlHandleA.x, controlHandleA.y); // 提交第一个控制点坐标。
glVertex2d(controlHandleB.x, controlHandleB.y); // 提交第二个控制点坐标。
glVertex2d(controlEnd.x, controlEnd.y); // 提交终点坐标。
}
void renderCoordinateAxes() { // 绘制坐标轴。
glColor3f(0.5f, 0.5f, 0.5f); // 设置坐标轴颜色为灰色。
glLineWidth(1.0f); // 设置坐标轴线宽。
glBegin(GL_LINES); // 开始绘制独立线段。
glVertex2d(-400.0, 0.0); // x 轴左端点。
glVertex2d(400.0, 0.0); // x 轴右端点。
glVertex2d(0.0, -200.0); // y 轴下端点。
glVertex2d(0.0, 400.0); // y 轴上端点。
glEnd(); // 结束坐标轴绘制。
}
void renderControlPolygon() { // 绘制连接控制点的折线。
glColor3f(0.0f, 0.0f, 1.0f); // 设置控制多边形颜色为蓝色。
glLineWidth(2.0f); // 设置控制多边形线宽。
glBegin(GL_LINE_STRIP); // 开始绘制连续折线。
submitControlVertices(); // 按顺序提交四个控制点。
glEnd(); // 结束控制多边形绘制。
}
void renderBezierCurve() { // 绘制三次 Bezier 曲线。
glColor3f(1.0f, 1.0f, 0.0f); // 设置曲线颜色为黄色。
glLineWidth(3.0f); // 设置曲线线宽。
double step = 1.0 / CURVE_SEGMENTS; // 计算每次增加的 t 步长。
glBegin(GL_LINE_STRIP); // 开始用连续折线近似绘制曲线。
for (double t = 0.0; t <= 1.0; t += step) { // 从 t=0 到 t=1 依次取点。
Vec2 curvePoint = calculateBezierPoint(t); // 计算当前 t 对应的曲线点。
glVertex2d(curvePoint.x, curvePoint.y); // 提交当前曲线点坐标。
}
glEnd(); // 结束曲线绘制。
}
void renderControlPoints() { // 绘制四个控制点。
glColor3f(1.0f, 0.0f, 0.0f); // 设置控制点颜色为红色。
glPointSize(8.0f); // 设置控制点大小。
glBegin(GL_POINTS); // 开始绘制点。
submitControlVertices(); // 提交四个控制点的位置。
glEnd(); // 结束控制点绘制。
}
void displayScene() { // GLUT 显示回调函数,负责绘制整个画面。
glClear(GL_COLOR_BUFFER_BIT); // 清空颜色缓冲区,准备重新绘制。
renderCoordinateAxes(); // 绘制坐标轴。
renderControlPolygon(); // 绘制控制多边形。
renderBezierCurve(); // 绘制 Bezier 曲线。
renderControlPoints(); // 绘制控制点。
glFlush(); // 强制执行前面的 OpenGL 绘图命令。
}
void initializeOpenGL() { // 初始化 OpenGL 绘图环境。
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置背景颜色为黑色。
glMatrixMode(GL_PROJECTION); // 切换到投影矩阵模式。
glLoadIdentity(); // 重置当前投影矩阵。
gluOrtho2D(-400.0, 400.0, -200.0, 400.0); // 设置二维正交投影范围。
}
int main(int argc, char** argv) { // 程序入口函数。
glutInit(&argc, argv); // 初始化 GLUT。
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 使用单缓冲和 RGB 颜色模式。
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); // 设置窗口大小。
glutInitWindowPosition(100, 100); // 设置窗口初始位置。
glutCreateWindow("实验4_01毕爽爽三次 Bezier 曲线"); // 创建窗口并设置标题。
initializeOpenGL(); // 初始化 OpenGL 参数。
glutDisplayFunc(displayScene); // 注册显示回调函数。
glutMainLoop(); // 进入 GLUT 主事件循环。
return 0; // 程序正常结束。
}