返回

OpenGL新手教程(二):正方形渲染与键盘控制

IOS

在这个OpenGL新手教程的第二部分中,我们将继续探索OpenGL图形编程的基础知识。在上一部分中,我们设置了OpenGL环境并绘制了一个三角形。在这部分中,我们将学习如何绘制一个正方形并使用键盘控制它的移动。

正方形渲染

定义正方形顶点坐标

一个正方形有四个顶点,坐标如下:

(-0.5, -0.5)
( 0.5, -0.5)
( 0.5,  0.5)
(-0.5,  0.5)

这些坐标定义了一个边长为1.0的正方形,其中心位于原点。

渲染环境设置

在绘制正方形之前,我们需要设置渲染环境。这包括设置视口、投影矩阵和模型矩阵。

// 设置视口
glViewport(0, 0, width, height);

// 设置投影矩阵
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

// 设置模型矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

开始绘制正方形

设置好渲染环境后,我们可以开始绘制正方形。首先,我们需要创建一个顶点缓冲对象(VBO)来存储正方形的顶点坐标。

// 创建一个VBO
GLuint vbo;
glGenBuffers(1, &vbo);

// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, vbo);

// 将顶点坐标传递到VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

接下来,我们需要创建一个顶点着色器和一个片段着色器。顶点着色器将处理顶点位置,而片段着色器将处理颜色。

// 创建一个顶点着色器
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);

// 加载并编译顶点着色器
const char* vertexShaderSource = ...
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);

// 创建一个片段着色器
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

// 加载并编译片段着色器
const char* fragmentShaderSource = ...
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);

// 创建一个着色器程序
GLuint shaderProgram;
shaderProgram = glCreateProgram();

// 将顶点着色器和片段着色器附加到着色器程序
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);

// 链接着色器程序
glLinkProgram(shaderProgram);

最后,我们可以绘制正方形。

// 使用着色器程序
glUseProgram(shaderProgram);

// 启用顶点数组
glEnableVertexAttribArray(0);

// 设置顶点属性指针
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

// 绘制正方形
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

键盘控制

要使用键盘控制正方形的移动,我们需要注册一个回调函数来处理键盘事件。

void keyboard(unsigned char key, int x, int y) {
    switch (key) {
        case 'w':
            // 向上移动
            break;
        case 's':
            // 向下移动
            break;
        case 'a':
            // 向左移动
            break;
        case 'd':
            // 向右移动
            break;
    }
}

然后,我们需要注册这个回调函数。

glutKeyboardFunc(keyboard);

矩阵更新

为了实现平滑的移动,我们需要更新模型矩阵以反映正方形的当前位置。

void updateMatrix() {
    // 平移模型矩阵
    glTranslatef(x, y, 0.0);
}

在主循环中,我们需要调用updateMatrix()函数来更新模型矩阵。

int main() {
    // ...

    while (true) {
        // ...

        updateMatrix();

        // ...
    }

    return 0;
}

完整代码

以下代码展示了如何绘制一个正方形并使用键盘控制它的移动:

#include <GL/glut.h>

// 正方形顶点坐标
GLfloat vertices[] = {
    -0.5f, -0.5f,
     0.5f, -0.5f,
     0.5f,  0.5f,
    -0.5f,  0.5f
};

// 键盘事件处理函数
void keyboard(unsigned char key, int x, int y) {
    switch (key) {
        case 'w':
            // 向上移动
            break;
        case 's':
            // 向下移动
            break;
        case 'a':
            // 向左移动
            break;
        case 'd':
            // 向右移动
            break;
    }
}

// 模型矩阵更新函数
void updateMatrix() {
    // 平移模型矩阵
    glTranslatef(x, y, 0.0);
}

int main() {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("OpenGL新手教程(二):正方形渲染与键盘控制");

    // 设置视口
    glViewport(0, 0, 500, 500);

    // 设置投影矩阵
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

    // 设置模型矩阵
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // 创建一个VBO
    GLuint vbo;
    glGenBuffers(1, &vbo);

    // 绑定VBO
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // 将顶点坐标传递到VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 创建一个顶点着色器
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);

    // 加载并编译顶点着色器
    const char* vertexShaderSource = ...
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    // 创建一个片段着色器
    GLuint fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

    // 加载并编译片段着色器
    const char* fragmentShaderSource = ...
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    // 创建一个着色器程序
    GLuint shaderProgram;
    shaderProgram = glCreateProgram();

    // 将顶点着色器和片段着色器附加到着色器程序
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    // 链接着色器程序
    glLinkProgram(shaderProgram);

    // 使用着色器程序
    glUseProgram(shaderProgram);

    // 启用顶点数组
    glEnableVertexAttribArray(0);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    // 注册键盘事件处理函数
    glutKeyboardFunc(keyboard);

    // 进入主循环
    while (true) {
        glClear(GL_COLOR_BUFFER_BIT);

        // 更新模型矩阵
        updateMatrix();

        // 绘制正方形
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glutSwapBuffers();
    }

    return 0;
}