本章参考官方教程:learnopengl-cn

VertexShader.glsl

#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
uniform mat4 projection; // 投影矩阵
out vec4 ourColor;	
void main()
{
    gl_Position = projection * vec4(position,1.0f);
    ourColor = vec4(color,1.0f);
}

FragmentShader.glsl

#version 330 core
in vec4 ourColor;
out vec4 FragColor;
void main()
{
	FragColor = ourColor;
}

GlslDealConfig.h

#pragma once

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

class GlslDealConfig
{
    public:
        GlslDealConfig() {}
        ~GlslDealConfig() {}
    
    public:
        std::string ReadGlslFile(const std::string& filename);

};

GlslDealConfig.cpp

#include "GlslDealConfig.h"

std::string GlslDealConfig::ReadGlslFile(const std::string& filename)
{
    std::string data;
    std::ifstream ifs(filename,std::ios::in);
    if(!ifs.is_open())
    {
        printf("open %s failed",filename.c_str());
        return data;
    }
    std::ostringstream fs;
    fs << ifs.rdbuf();
    data = fs.str();
    return data;
}

main.cpp

#include <iostream>

#include "glew.h"
#include "glfw3.h"

#include "glm/glm.hpp"                  // GLM 的基本数学类型,例如 glm::mat4 和 glm::vec3
#include "glm/gtc/matrix_transform.hpp" // GLM 的矩阵变换函数,例如 glm::ortho
#include "glm/gtc/type_ptr.hpp"         // 用于 glm::value_ptr 函数


#include "log.h"
#include "GlslDealConfig.h"

GLfloat vertices_1[] = 
{
	0.0f, 0.0f, 0.0f,		// 上顶点
	700.0f, 0.0f, 0.0f,		// 左顶点
	700.0f, 700.0f, 0.0f,	// 右顶点
	
};

GLfloat vertices_2[] = 
{
	1.0f, 0.0f, 0.0f,		// 上顶点
	0.0f, 1.0f, 0.0f,		// 左顶点
	0.0f, 0.0f, 1.0f,		// 右顶点
	
};

int main()
{
    GlslDealConfig mdeal;
    int major = 0, minor = 0, rev = 0;
    glfwGetVersion(&major, &minor, &rev);
    LOGI("glfw version %d - %d - %d", major,minor,rev);

    if (glfwInit() == GLFW_FALSE)
    {
        LOGE("glfwInit failed");
        return 0;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(700, 700, "Hello OpenGL", NULL, NULL);
    if (window == NULL)
    {
        LOGE("glfwCreateWindow failed");
        return 0;
    }

    glfwMakeContextCurrent(window);

    GLenum err = glewInit();
    if (err != GLEW_OK)
    {
        LOGE("glew init failed : %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
        return 0;
    }

    glfwSwapInterval(1);

    std::string vertexShader = mdeal.ReadGlslFile("/home/ryan/zxp/Rendering/glsl/VaoAndVbo/VertexShader.glsl");
    std::string fragmentShader = mdeal.ReadGlslFile("/home/ryan/zxp/Rendering/glsl/VaoAndVbo/FragmentShader.glsl");

    const GLchar *vData = vertexShader.c_str();
    const GLchar *fData = fragmentShader.c_str();

    GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(vShader, 1, &vData, NULL);
    glShaderSource(fShader, 1, &fData, NULL);
    glCompileShader(vShader);
    glCompileShader(fShader);

    GLuint progma = glCreateProgram();
    glAttachShader(progma, vShader);
    glAttachShader(progma, fShader);
    glLinkProgram(progma);

    glDeleteShader(vShader);
    glDeleteShader(fShader);

    GLuint VAO, VBO[2];
    glGenVertexArrays(1, &VAO);
    glGenBuffers(2, VBO);

    glBindVertexArray(VAO);

    // 绑定第一个 VBO 并设置顶点属性指针
    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_1), vertices_1, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    // 绑定第二个 VBO 并设置顶点属性指针
    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_2), vertices_2, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(1);

    // 解绑 VAO
    glBindVertexArray(0);

    glm::mat4 projection = glm::ortho(0.0f, 600.0f, 0.0f, 600.0f, -1.0f, 1.0f);
    glUseProgram(progma);
    GLuint projLoc = glGetUniformLocation(progma, "projection");
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // 绘制循环
    while (!glfwWindowShouldClose(window))
    {
        glViewport(0, 0, 700, 700);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

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

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(2, VBO);
    glDeleteProgram(progma);

    glfwTerminate();

    return 0;
}

OpengGL教程(三)---使用VAO和VBO方式绘制三角形_c++

1、为什么要先绑定VAO在设置顶点属性然后解绑VAO?

在 OpenGL 中,使用顶点数组对象(VAO)可以方便地管理顶点属性的状态。绑定 VAO、设置顶点属性、然后解绑 VAO 的顺序是为了确保顶点属性的设置被正确地记录在 VAO 中,从而简化渲染代码并提高效率。

2、为什么有两次glUseProgram

设置Uniform变量之前必须使用正确的着色器程序
在调用 glUniformMatrix4fv 来设置 projection 矩阵之前,你必须激活(或使用)你要更新的着色器程序(progma)。glUniformMatrix4fv 更新的是当前使用的着色器程序中的 projection uniform 变量。
因此,如果你在设置 uniform 变量之前没有使用正确的着色器程序,那么 glUniformMatrix4fv 将无法正确更新 uniform 变量,这可能导致渲染结果不正确或无法渲染。

在 glUseProgram(progma); 调用之后,所有的着色器相关的操作(如设置 uniform 变量、绘制调用)都将作用于 progma。如果你在设置 uniform 变量之前没有调用 glUseProgram(progma);,那么 uniform 设置将不会生效,因为你没有切换到正确的着色器程序。

绘制循环中的 glUseProgram(progma); 确保在绘制操作时,使用的是正确的着色器程序。
如果这个调用被省略,绘制操作将不会使用你期望的着色器程序,可能导致渲染结果错误。

运行截图

OpengGL教程(三)---使用VAO和VBO方式绘制三角形_cmake_02


感谢阅读^ _ ^

如有错误感谢指正。