(OpenGL入门教程:从零开始绘制你的第一个三角形)

在这里插入图片描述

1. 🛠 环境准备

在开始开发OpenGL应用程序之前,我们需要准备好开发环境。我们将使用GLFW来创建窗口和处理输入,并使用GLEW来加载OpenGL函数。

1.1 安装OpenGL和GLFW

1.1.1 在Ubuntu上安装

在Ubuntu上,你可以使用包管理器安装GLFW和GLEW:

sudo apt-get update
sudo apt-get install libglfw3-dev libglew-dev

1.1.2 在Windows上安装

  1. 下载并安装MinGW或Visual Studio。
  2. 从GLFW官网(https://www.glfw.org/download.html)下载GLFW库。
  3. 从GLEW官网(http://glew.sourceforge.net/)下载GLEW库。

2. 🎨 创建一个简单的OpenGL程序

下面是一个简单的OpenGL程序,它创建一个窗口并在其中绘制一个三角形。

2.1 代码示例

首先,我们创建一个新的C++文件(例如main.cpp),并添加以下代码:

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

// 顶点着色器代码
const char* vertexShaderSource = R"(
#version 330 core
layout(location = 0) in vec3 aPos;
void main()
{
    gl_Position = vec4(aPos, 1.0);
}
)";

// 片段着色器代码
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 FragColor;
void main()
{
    FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}
)";

int main() {
    // 初始化GLFW
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW" << std::endl;
        return -1;
    }

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Window", NULL, NULL);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // 初始化GLEW
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW" << std::endl;
        return -1;
    }

    // 编译顶点着色器
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    // 检查顶点着色器编译错误
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    // 编译片段着色器
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    // 检查片段着色器编译错误
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    // 链接着色器程序
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    // 检查链接错误
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }

    // 删除着色器
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 定义顶点数据
    float vertices[] = {
         0.0f,  0.5f, 0.0f, // 顶点1
        -0.5f, -0.5f, 0.0f, // 顶点2
         0.5f, -0.5f, 0.0f  // 顶点3
    };

    // 创建顶点缓冲对象 (VBO) 和顶点数组对象 (VAO)
    GLuint VBO, VAO;
    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(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 解绑VAO
    glBindVertexArray(0);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {
        // 处理输入
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
            glfwSetWindowShouldClose(window, true);
        }

        // 渲染
        glClear(GL_COLOR_BUFFER_BIT);

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

        // 绑定VAO
        glBindVertexArray(VAO);

        // 绘制三角形
        glDrawArrays(GL_TRIANGLES, 0, 3);

        // 交换缓冲
        glfwSwapBuffers(window);

        // 轮询事件
        glfwPollEvents();
    }

    // 删除资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);

    // 终止GLFW
    glfwTerminate();
    return 0;
}

2.2 代码解析

  1. 初始化GLFW:调用glfwInit()函数初始化GLFW库,如果初始化失败则退出程序。
  2. 创建窗口:使用glfwCreateWindow()函数创建一个800x600的窗口,并将其上下文设置为当前线程的上下文。
  3. 初始化GLEW:调用glewInit()函数初始化GLEW库,如果初始化失败则退出程序。
  4. 编译和链接着色器
    • 创建顶点着色器和片段着色器。
    • 编译着色器并检查编译错误。
    • 链接着色器程序并检查链接错误。
  5. 定义顶点数据:定义一个包含三角形顶点数据的数组。
  6. 创建VBO和VAO:生成并绑定顶点缓冲对象(VBO)和顶点数组对象(VAO),将顶点数据传递到缓冲区,并设置顶点属性指针。
  7. 渲染循环:在渲染循环中处理输入、渲染三角形、交换缓冲并轮询事件。
  8. 删除资源并终止GLFW:在退出程序前删除所有资源并终止GLFW。

2.3 编译和运行

将上述代码保存为main.cpp,然后使用以下命令编译并运行:

在Linux上

g++ main.cpp -o opengl_example -lglfw -lGLEW -lGL
./opengl_example

在Windows上(使用MinGW)

g++ main.cpp -o opengl_example -lglfw3 -lglew32 -lopengl32
./opengl_example.exe

3. 🚀 总结

恭喜你!你已经成功创建了一个使用OpenGL绘制简单三角形的程序。接下来,你可以尝试以下扩展:

  1. 添加颜色:修改顶点着色器和片段着色器,为每个顶点添加颜色属性。
  2. 纹理映射:学习如何在三角形上应用纹理。
  3. 3D图形:探索如何使用OpenGL绘制3D图形和实现相机视角。

希望这篇博客能帮助你更好地理解和应用OpenGL。