📜  使用OpenGL渲染三角形(使用着色器)(1)

📅  最后修改于: 2023-12-03 15:06:52.860000             🧑  作者: Mango

使用OpenGL渲染三角形 (使用着色器)

在OpenGL中使用着色器可以实现更加高级的渲染效果。在本文中,我们将讨论如何使用OpenGL渲染三角形,并使用着色器为其添加颜色。

1. 设置OpenGL环境

在开始使用OpenGL渲染三角形之前,需要设置OpenGL环境。下面是一个示例:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>

int main() {
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Initialize GLEW */
    if (glewInit() != GLEW_OK)
        std::cout << "Error initializing GLEW" << std::endl;

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

以上代码创建了一个窗口,并将其设置为当前的OpenGL上下文。

2. 创建三角形

创建三角形有两种方法:使用顶点数组和使用顶点缓冲区对象(VBO)。在本文中,我们将使用顶点数组。

GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
};

GLuint VAO, VBO;

glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);

glBindVertexArray(0);

以上代码创建了一个具有三个顶点的三角形,并将其存储在顶点数组中。然后使用 glGenVertexArrays 函数和 glGenBuffers 函数分别生成顶点数组对象和缓冲区对象,并绑定它们。

使用 glBindVertexArray 函数和 glBindBuffer 函数将缓冲区绑定到当前的顶点数组对象中。然后使用 glBufferData 函数将顶点数组复制到缓冲区中。

使用 glVertexAttribPointer 函数配置顶点属性指针,并使用 glEnableVertexAttribArray 函数启用它。

使用 glBindVertexArray 函数将当前的顶点数组对象解绑。

3. 编写着色器

着色器是用于渲染图形的编程语言,它们通过将输入顶点转换为输出颜色来渲染图形。在本文中,我们将编写顶点着色器和片段着色器。

const GLchar* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "void main()\n"
    "{\n"
    "    gl_Position = vec4(position.x, position.y, position.z, 1.0f);\n"
    "}\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"
    "out vec4 color;\n"
    "void main()\n"
    "{\n"
    "    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\0";

GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);

GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);

GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

以上代码分别定义了顶点着色器和片段着色器。顶点着色器将每个输入顶点转换为带有四个分量的裁剪空间坐标(即 gl_Position 变量)。片段着色器将输出单个颜色,我们使用 vec4 类型的 color 变量表示其 RGBA 值。

使用 glCreateShader 函数创建顶点着色器对象和片段着色器对象,并使用 glShaderSource 函数将着色器源代码附加到着色器对象上。然后使用 glCompileShader 函数编译着色器。

使用 glCreateProgram 函数创建着色器程序对象,并使用 glAttachShader 函数将顶点着色器和片段着色器附加到着色器程序上。然后使用 glLinkProgram 函数链接着色器程序。

使用 glDeleteShader 函数删除顶点着色器和片段着色器对象。

4. 渲染三角形

现在我们准备好渲染三角形了。使用以下代码在窗口中绘制三角形:

glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3); 
glBindVertexArray(0);

使用 glUseProgram 函数指定要使用的着色器程序。使用 glBindVertexArray 函数指定要使用的顶点数组对象,并使用 glDrawArrays 函数绘制三角形。然后使用 glBindVertexArray 函数将当前的顶点数组对象解绑。

5. 完整代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>

const GLchar* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "void main()\n"
    "{\n"
    "    gl_Position = vec4(position.x, position.y, position.z, 1.0f);\n"
    "}\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"
    "out vec4 color;\n"
    "void main()\n"
    "{\n"
    "    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\0";

int main() {
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Initialize GLEW */
    if (glewInit() != GLEW_OK)
        std::cout << "Error initializing GLEW" << std::endl;

    GLfloat vertices[] = {
        -0.5f, -0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
         0.0f,  0.5f, 0.0f
    };

    GLuint VAO, VBO;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindVertexArray(0);

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3); 
        glBindVertexArray(0);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

参考资料

  1. LearnOpenGL
  2. OpenGL Development Cookbook, 1st Edition, by Muhammad Mobeen Movania