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

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

VertexShader.glsl

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

glsl 复制代码
#version 330 core
in vec4 ourColor;
out vec4 FragColor;
void main()
{
	FragColor = ourColor;
}

GlslDealConfig.h

cpp 复制代码
#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

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

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;
}

解释: 解释: 解释:

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); 确保在绘制操作时,使用的是正确的着色器程序。

如果这个调用被省略,绘制操作将不会使用你期望的着色器程序,可能导致渲染结果错误。

运行截图

感谢阅读^ _ ^

如有错误感谢指正。

联系我的方式
Q Q : 918619587 QQ : 918619587 QQ:918619587

相关推荐
小欣加油2 小时前
leetcode1926 迷宫中离入口最近的出口
数据结构·c++·算法·leetcode·职场和发展
做cv的小昊2 小时前
计算机图形学:【Games101】学习笔记08——光线追踪(辐射度量学、渲染方程与全局光照、蒙特卡洛积分与路径追踪)
图像处理·笔记·学习·计算机视觉·游戏引擎·图形渲染·概率论
星恒随风3 小时前
C++ 类和对象入门(五):初始化列表、explicit 和 static 成员详解
开发语言·c++·笔记·学习·状态模式
浪客灿心3 小时前
项目篇:模块设计与实现
数据库·c++
牛油果子哥q3 小时前
【C++ STL vector】C++ STL vector 终极精讲:动态数组底层原理、两倍扩容机制、迭代器失效、增删查改、性能剖析与工程避坑指南
开发语言·c++
硅谷秋水3 小时前
HumanEgo:基于人类第一人称视角数分钟视频的零样本机器人学习
人工智能·机器学习·计算机视觉·机器人
gis分享者4 小时前
OpenCV 新手入门与实战部署指南
人工智能·opencv·计算机视觉
OpenBayes贝式计算4 小时前
教程上新丨16GB 笔记本跑出接近 26B MoE 性能,Gemma 4 12B 基于创新架构统一处理文本 / 图像 / 声音三种模态
计算机视觉·google·agent
为何创造硅基生物5 小时前
独占指针的创建std::make_unique 本身自带堆出现
c++
kyle~5 小时前
ROS 2 与 Isaac Sim 联合仿真(一)体系架构、环境选型与基础通信闭环
c++·机器人·nvidia·仿真·ros2