Linux OpenGL(3) —— 一个三角形

发布时间 2023-12-26 13:27:50作者: Torch_HXM

绘制图形的大致流程

image
图中,浅蓝色方格是整个过程中的重要对象。

准备顶点坐标,创建VAO,并将坐标存入VBO

GLfloat vertices[] = {                                                      // 顶点位置
	-0.5, -0.5, 0,
	0.5, -0.5, 0,
	0, 0.5, 0
	};

unsigned int VAO;                                                           // 用以储存当前VBO和顶点属性
glGenVertexArrays(1, &VAO);                                                 // 创建一个顶点数组对象
glBindVertexArray(VAO);                                                     // 绑定顶点数组对象,这样后面的VBO才会被记录

unsigned int VBO;
glGenBuffers(1, &VBO);                                                      // 生成一个缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);                                         // 将缓冲对象与顶点缓冲区VAO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  // 将数据写入顶点缓冲区,第四个参数描述了数据在未来是否会发生剧烈改变, GL_STATIC_DRAW 代表几乎不会改变

创建顶点着色器对象

const char* vertexShaderSource = "#version 330 core\n"                      // 顶点着色器的源码
	"layout (location = 0) in vec3 aPos;\n"
	"void main(){\n"
	"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
	"}\0"; 

unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);                            // 创建一个顶点着色器对象

glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);                 // 将着色器对象与源码进行装配。第二个参数为着色器源码的数量。
glCompileShader(vertexShader);                                              // 编译着色器

GLint issuccess;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &issuccess);                 // 检查编译是否成功
if(!issuccess){
	glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);               // 如果编译失败则获得错误信息
	std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
	abort();
}

创建片段着色器对象

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

unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);                        // 创建一个片段着色器对象
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);             // 将片段着色器与源码进行装配
glCompileShader(fragmentShader);                                            // 编译片段着色器

glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &issuccess);               // 检查编译是否成功
if(!issuccess){
	glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);             // 如果编译失败则获得错误信息
	std::cout << "ERROR::SHADER::FRAGEMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
	abort();
}

创建程序对象

unsigned int shaderProgram;
shaderProgram = glCreateProgram();                                          // 创建一个程序对象
glAttachShader(shaderProgram, vertexShader);                                // 让程序对象包含的那个点着色器
glAttachShader(shaderProgram, fragmentShader);                              // 让程序对象包含片段着色器
glLinkProgram(shaderProgram);                                               // 链接程序

glGetProgramiv(shaderProgram, GL_LINK_STATUS, &issuccess);                  // 检查链接是否成功
if(!issuccess){
	glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);             // 失败时获得报错信息
	std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << infoLog << std::endl;
	abort();
}

声明顶点的内存排列形式

glDeleteShader(vertexShader);glDeleteShader(fragmentShader);                    // 删除不再需要的着色器对象
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (void*)0);   // 告诉 openGL 我们的顶点数据的内存排列形式。参数:起始位置、每组数据个数、数据类型、是否归一化、每一组数据的大小、起始位置序号的指针。
glEnableVertexAttribArray(0);                                                   // 启用顶点属性

这里的起始位置是 0 是因为我们在顶点着色器中声明了 location = 0

绘制三角形

// 主循环
while(!glfwWindowShouldClose(window)){
	// 检查输入
	...
	// 渲染
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	glUseProgram(shaderProgram);                                            // 激活程序对象
	glBindVertexArray(VAO);                                                 // 指定使用的顶点数组对象
	glDrawArrays(GL_TRIANGLES, 0, 3);                                       // 绘制三角形。参数:图形模式、数据起点、点个数
	// 更新
	glfwSwapBuffers(window);
	glfwPollEvents();
}

整体代码

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

void frameBufferSizeCallback(GLFWwindow* window, int width, int height);
void checkInput(GLFWwindow* window);

int main(){
    // 窗口初始化
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    GLFWwindow* window = glfwCreateWindow(800, 600, "opengl test window", NULL, NULL);
    if(window==NULL){
        std::cout<< "Failed to create window with glfw.\n";
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
        std::cout<< "Failed to initalize glad.\n";
        return -1;
    }
    glViewport(0, 0, 800, 600);
    glfwSetFramebufferSizeCallback(window, frameBufferSizeCallback);
    
    // 绘制

    GLfloat vertices[] = {                                                      // 顶点位置
        -0.5, -0.5, 0,
        0.5, -0.5, 0,
        0, 0.5, 0
    };

    unsigned int VAO;                                                           // 用以储存当前VBO和顶点属性
    glGenVertexArrays(1, &VAO);                                                 // 创建一个顶点数组对象
    glBindVertexArray(VAO);                                                     // 绑定顶点数组对象,这样后面的VBO才会被记录

    unsigned int VBO;
    glGenBuffers(1, &VBO);                                                      // 生成一个缓冲对象
    glBindBuffer(GL_ARRAY_BUFFER, VBO);                                         // 将缓冲对象与顶点缓冲区VAO绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  // 将数据写入顶点缓冲区,第四个参数描述了数据在未来是否会发生剧烈改变, GL_STATIC_DRAW 代表几乎不会改变

    const char* vertexShaderSource = "#version 330 core\n"                      // 顶点着色器的源码
    "layout (location = 0) in vec3 aPos;\n"
    "void main(){\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0"; 

    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);                            // 创建一个顶点着色器对象

    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);                 // 将着色器对象与源码进行装配。第二个参数为着色器源码的数量。
    glCompileShader(vertexShader);                                              // 编译着色器

    GLint issuccess;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &issuccess);                 // 检查编译是否成功
    if(!issuccess){
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);                   // 如果编译失败则获得错误信息
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        abort();
    }

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

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);                        // 创建一个片段着色器对象
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);             // 将片段着色器与源码进行装配
    glCompileShader(fragmentShader);                                            // 编译片段着色器

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &issuccess);               // 检查编译是否成功
    if(!issuccess){
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);                 // 如果编译失败则获得错误信息
        std::cout << "ERROR::SHADER::FRAGEMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        abort();
    }
    
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();                                          // 创建一个程序对象
    glAttachShader(shaderProgram, vertexShader);                                // 让程序对象包含的那个点着色器
    glAttachShader(shaderProgram, fragmentShader);                              // 让程序对象包含片段着色器
    glLinkProgram(shaderProgram);                                               // 链接程序

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &issuccess);                  // 检查链接是否成功
    if(!issuccess){
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);                 // 失败时获得报错信息
        std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << infoLog << std::endl;
        abort();
    }

    glDeleteShader(vertexShader);glDeleteShader(fragmentShader);                    // 删除不再需要的着色器对象
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (void*)0);   // 告诉 openGL 我们的顶点数据的内存排列形式。参数:起始位置、每组数据个数、数据类型、是否归一化、每一组数据的大小、起始位置序号的指针。
    glEnableVertexAttribArray(0);                                                   // 启用顶点属性

    // 主循环
    while(!glfwWindowShouldClose(window)){
        // 检查输入
        checkInput(window);
        // 渲染
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glUseProgram(shaderProgram);                                            // 激活程序对象
        glBindVertexArray(VAO);                                                 // 指定使用的顶点数组对象
        glDrawArrays(GL_TRIANGLES, 0, 3);                                       // 绘制三角形。参数:图形模式、数据起点、点个数
        // 更新
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwTerminate();
    return 0;
}
// g++ -o out main.cpp lib/glad.c -lglfw -lGL -lm -lXrandr -lXi -lX11 -lXxf86vm -lpthread -ldl -lXinerama -lXcursor

void frameBufferSizeCallback(GLFWwindow* window, int width, int height){glViewport(0, 0, width, height);}// 设置回调函数
void checkInput(GLFWwindow* window){
	if(glfwGetKey(window, GLFW_KEY_ESCAPE)==GLFW_PRESS){
        glfwSetWindowShouldClose(window, 1);
    }
}

参考链接你好,三角形