You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改OpenGL代码,用GL_MAP1_VERTEX_3生成6条贝塞尔曲线?

问题

尝试用OpenGL创建自定义曲线形状,但当前代码仅能在指定控制点之间生成一条曲线。现有OpenGL代码如下:

#include <GL/glut.h>
#include <stdlib.h>

GLfloat controlPoints[18][3] =
{
    {0.0, 8.0, 0.0},
    { -1.5, 3.0, 0.0}, //2
    {-5.5, 4.0, 0.0},

    {-5.5, 4.0, 0.0},
    {-2.5, 0.0, 0.0}, //4
    {-6.0, -4.0, 0.0}, 

    {-6.0, -4.0, 0.0},
    {-1.5, -3.0, 0.0}, //6
    {0.0, -8.0, 0.0},
    
    {0.0, -8.0, 0.0},
    {1.0, -3.0, 0.0}, //8
    {6.0, -5.0, 0.0},

    {6.0, -5.0, 0.0},
    {3.0, 0.0, 0.0}, //10
    {6.5, 4.5, 0.0},
    
    {6.5, 4.5, 0.0},
    {1.5, 3.0, 0.0}, //12
    {0.0, 8.0, 0.0}
    
};

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    for (int i = 0; (i + 3) < 3; i += 3)
    {
        glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &controlPoints[i][0]);
    }
    glEnable(GL_MAP1_VERTEX_3);
}

void display(void)
{
    int i;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);

    glBegin(GL_LINE_STRIP);
    {
        for (int i = 0; i <= 18; i++)
        {
            glEvalCoord1f((GLfloat)i / 18.0);
        }
    }
    glEnd();

    glBegin(GL_LINE_STRIP);
    {
        for (i = 0; i < 18; i++)
        {
            glVertex3fv(&controlPoints[i][0]);

        }
    }
    glEnd();

glPointSize(6.0);
    glColor3f(0.0, 0.0, 1.0);
    glBegin(GL_POINTS);
    {
        for (i = 0; i < 18; i++)
        {
            glVertex3fv(&controlPoints[i][0]);

        }
    }
    glEnd();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    {
        glOrtho(-10.0, 10.0, -10.0 * (GLfloat)h / (GLfloat)w, 10.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0);
    }
    else
    {
        glOrtho(-10.0 * (GLfloat)h / (GLfloat)w, 10.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0, -10.0, 10.0);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 27:
        exit(0);
        break;
    }
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}

当前仅能生成一条曲线,需要基于这18个控制点生成6条曲线,询问如何修改init函数实现;若无法用GL_MAP1_VERTEX_3实现,是否可以用GL_LINE_STRIP完成?

解决方案

方法一:使用GL_MAP1_VERTEX_3生成多条贝塞尔曲线

你的控制点按每3个新点+1个衔接点的方式分组,每组4个控制点对应一条3次贝塞尔曲线,共6组。原init函数的循环条件错误(i + 3 < 3永远不成立),且glMap1f是设置当前的映射参数,不能一次性设置多组,需要在display中循环为每组控制点设置映射,再生成曲线。

修改后的init和display函数:

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glEnable(GL_MAP1_VERTEX_3); // 只需要启用一次
}

void display(void)
{
    int i, j;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);

    // 生成6条贝塞尔曲线
    for(j = 0; j < 18; j += 3) // 每组3个新控制点,加上衔接点共4个
    {
        // 设置当前组的控制点映射
        glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &controlPoints[j][0]);
        glBegin(GL_LINE_STRIP);
        {
            // 对每条曲线采样20个点,保证平滑度
            for(i = 0; i <= 20; i++)
            {
                glEvalCoord1f((GLfloat)i / 20.0);
            }
        }
        glEnd();
    }

    // 绘制控制点连线(原代码保留)
    glBegin(GL_LINE_STRIP);
    {
        for (i = 0; i < 18; i++)
        {
            glVertex3fv(&controlPoints[i][0]);
        }
    }
    glEnd();

    // 绘制控制点(原代码保留)
    glPointSize(6.0);
    glColor3f(0.0, 0.0, 1.0);
    glBegin(GL_POINTS);
    {
        for (i = 0; i < 18; i++)
        {
            glVertex3fv(&controlPoints[i][0]);
        }
    }
    glEnd();

    glFlush(); // 确保绘制命令执行
}

方法二:使用GL_LINE_STRIP绘制近似贝塞尔曲线

如果不想用OpenGL的 evaluator,可以手动实现贝塞尔曲线的点计算,然后用GL_LINE_STRIP连接采样点来模拟曲线。

首先添加一个计算贝塞尔曲线上点的函数:

void bezierPoint(GLfloat t, GLfloat* p, GLfloat* cp)
{
    GLfloat u = 1 - t;
    GLfloat u2 = u * u;
    GLfloat u3 = u2 * u;
    GLfloat t2 = t * t;
    GLfloat t3 = t2 * t;

    // 3次贝塞尔曲线公式
    p[0] = u3 * cp[0] + 3 * u2 * t * cp[3] + 3 * u * t2 * cp[6] + t3 * cp[9];
    p[1] = u3 * cp[1] + 3 * u2 * t * cp[4] + 3 * u * t2 * cp[7] + t3 * cp[10];
    p[2] = u3 * cp[2] + 3 * u2 * t * cp[5] + 3 * u * t2 * cp[8] + t3 * cp[11];
}

然后修改display函数,循环计算每组控制点的采样点并绘制:

void display(void)
{
    int i, j;
    GLfloat p[3];

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);

    // 绘制6条近似贝塞尔曲线
    for(j = 0; j < 18; j += 3)
    {
        glBegin(GL_LINE_STRIP);
        {
            for(i = 0; i <= 20; i++)
            {
                GLfloat t = (GLfloat)i / 20.0;
                bezierPoint(t, p, &controlPoints[j][0]);
                glVertex3fv(p);
            }
        }
        glEnd();
    }

    // 绘制控制点连线和控制点(原代码保留)
    glBegin(GL_LINE_STRIP);
    {
        for (i = 0; i < 18; i++)
        {
            glVertex3fv(&controlPoints[i][0]);
        }
    }
    glEnd();

    glPointSize(6.0);
    glColor3f(0.0, 0.0, 1.0);
    glBegin(GL_POINTS);
    {
        for (i = 0; i < 18; i++)
        {
            glVertex3fv(&controlPoints[i][0]);
        }
    }
    glEnd();

    glFlush();
}

说明

  • 方法一利用OpenGL内置的 evaluator 生成标准贝塞尔曲线,代码更简洁;
  • 方法二手动计算贝塞尔点,灵活性更高,不需要依赖OpenGL的 evaluator 特性。

内容的提问来源于stack exchange,提问作者sali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:15:44