OpenGL:三角形(中文注释版)

Triangle是LearnOpenGL CN教程中的第二个项目,里面包含了完整的OpenGL渲染流程,后续的所有程序都是基于此程序的。这个程序就像c语言中输出"Hello World"一样,很有必要每一行代码都精读。最近在复习之前学习的OpenGL时,发现有些基本的概念比较模糊,于是对照着重新写了一遍,把每个比较重要的地方都加了中文注释,方便以后自己查阅。此代码基于Linux下的Clion编写,项目目录如下:

 

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(Triangle)
set(CMAKE_CXX_STANDARD 14)
set(SOURCE_FILES main.cpp glad.c)
add_executable(Triangle ${SOURCE_FILES})
target_link_libraries(Triangle glfw3 GL m Xrandr Xi X11 Xxf86vm pthread dl Xinerama Xcursor)

 

main.cpp 

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

void processInput(GLFWwindow *window);  // 处理键盘/鼠标的输入

// 设置窗口大小
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// 顶点着色器
const char *vertexShaderSource = "#version 330 core\n"
                                 "layout (location = 0) in vec3 aPos;\n"   //输入变量的位置值
                                 "void main()\n"
                                 "{\n"
                                 "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"    //顶点着色器的输出
                                 "}\0";
// 片段着色器
const char *fragmentShaderSource = "#version 330 core\n"
                                   "out vec4 FragColor;\n"    //输出变量
                                   "void main()\n"
                                   "{\n"
                                   "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"    //片段着色器的输出
                                   "}\n\0";


int main() {
    // glfw的初始化和配置
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);  // 设置主版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);  // 设置次版本
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用OpenGL核心模式

// 如果是苹果电脑,需要加上这个
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif

    // 创建OpenGL窗口
    // -------------------------------------------------------------------------------------------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Triangle", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);  // 将窗口的上下文设置为当前线程的主上下文

    // 初始化glad,加载OpenGL函数指针地址的函数
    // -----------------------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    // 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
    glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);

    // 创建和编译着色器
    // --------------------------------------------------------
    // 顶点着色器
    int 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::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // 片段着色器
    int 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::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // 链接着色器程序
    int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // 检查链接是否成功
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    // 链接成功后删除着色器
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    // 设置VAO,VBO,顶点属性等
    // ------------------------------------------------------------------
    // 三角形的三个顶点数据
    float vertices[] = {
            -0.5f, -0.5f, 0.0f, // left
            0.5f, -0.5f, 0.0f, // right
            0.0f,  0.5f, 0.0f  // top
    };

    // 生成并绑定VAO,VBO
    GLuint VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    GLuint VBO;
    glGenBuffers(1, &VBO);   // 第一个参数是要生成的缓冲对象的数量,第二个是要输入用来存储缓冲对象名称的数组
    glBindBuffer(GL_ARRAY_BUFFER, VBO);    // 把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);    // 把之前定义的顶点数据复制到缓冲的内存中

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	/* 第一个参数指定我们要配置的顶点属性,为layout(location = 0)定义的position顶点属性的位置值(Location)
	第二个参数指定顶点属性的大小。顶点属性是一个vec3,它由3个值组成,所以大小是3。
	第三个参数指定数据的类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。
	第四个个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSE。
	第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在3个float之后,我们把步长设置为3 * sizeof(float)。*/
    glEnableVertexAttribArray(0);
    /* 每个顶点属性从一个VBO管理的内存中获得它的数据,而具体是从哪个VBO(程序中可以有多个VBO)       
    获取则是通过在调用glVertexAttribPointer时绑定到GL_ARRAY_BUFFER的VBO决定的。由于在调用 
    glVertexAttribPointer之前绑定的是先前定义的VBO对象,顶点属性0现在会链接到它的顶点数据。*/

    // 解绑VAO和VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // 正常模式和线框模式
    //glPolygonMode(GL_FRONT_AND_BACK, GL_FULL);
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // 渲染循环
    // -----------------------------------
    while (!glfwWindowShouldClose(window))
    {
        // 处理输入
        processInput(window);

        // 渲染
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);   // 设置清空屏幕所用的颜色
        glClear(GL_COLOR_BUFFER_BIT);   // 清空屏幕的颜色缓冲,它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲

        // 画三角形
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        // glBindVertexArray(0);

        // 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 删除VAO和VBO
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    // 释放/删除之前的分配的所有资源,退出程序
    glfwTerminate();
    return 0;
}

void processInput(GLFWwindow *window)
{
    // 如果按下了esc键,关闭渲染窗口
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值