#include // 引入 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; // 程序正常结束。 }