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

本章参考官方教程: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;
}

解释: 解释: 解释:

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

### 回答1: OpenGLOpen Graphics Library)是一种跨平台的图形编程接口,可以用于开发2D和3D图形应用程序。下面是一些OpenGL项目实战教程: 1. 光照效果:学习如何使用OpenGL实现各种光照效果,例如平行光、点光源和聚光灯效果。通过调整光照参数和材质属性,可以创建逼真的光照场景。 2. 纹理映射:学习如何使用OpenGL将纹理映射到维模型上。通过加载图像文件并将其应用于模型表面,可以实现逼真的贴图效果。 3. 阴影效果:学习如何使用OpenGL实现阴影效果,例如投影阴影和阴影贴图。阴影效果可以增强场景的逼真感和深度感。 4. 粒子系统:学习如何使用OpenGL创建粒子系统,例如火焰、烟雾和爆炸效果。通过调整粒子属性和行为,可以创建各种动态和生动的效果。 5. 物理模拟:学习如何使用OpenGL结合物理引擎实现物理模拟效果,例如碰撞检测、重力和运动模拟。通过模拟真实世界的物理规律,可以创建更真实的交互体验。 6. 游戏开发:学习如何使用OpenGL和其他游戏开发库(例如SDL或SFML)开发2D或3D游戏。从游戏引擎的搭建到游戏场景的渲染,可以实现自己的游戏创意。 这些项目实战教程可以帮助初学者学习并掌握OpenGL的基本概念和技术,同时也可以帮助有一定OpenGL经验的程序员进一步提升他们的图形编程能力。通过实际动手实现这些项目,可以更好地理解OpenGL的原理和使用方法,并能够应用于实际的图形应用程序开发中。 ### 回答2: OpenGLOpen Graphics Library)是一个用于维图形渲染的跨平台开放式图形库。它提供了一系列的函数和工具,帮助开发人员创建高性能的图形应用程序。 关于OpenGL项目实战教程,我可以给出以下几个方面的建议: 首先,了解基础知识。在开始实战项目之前,需要掌握OpenGL的基本概念和原理,包括顶点缓冲对象、顶点数组对象、着色器、纹理等。可以通过查阅OpenGL的官方文档或相关教程来学习。 其次,选择一个合适的实战项目。可以根据自己的兴趣和实际需求选择一个合适的项目,比如创建一个简单的3D游戏、设计一个图形界面等。选择一个适合自己水平和时间的项目,逐步提升自己的技能。 然后,学习项目所需的技术和工具。根据项目的需求,可能需要学习一些额外的技术和工具,比如图形数学、碰撞检测、模型导入等。可以通过在线教程、书籍或论坛来学习这些知识,并逐步应用到自己的项目中。 接下来,编写代码并调试。根据项目需求,使用OpenGL提供的函数和工具编写代码,并对代码进行调试。可以通过输出调试信息、使用调试工具等方式来排查问题并解决。 最后,不断学习和优化。OpenGL是一个庞大而复杂的库,可能需要不断地学习和掌握新的技术和工具。在实战过程中,可以将学到的经验和技巧总结下来,并进行项目的优化,提高性能和用户体验。 总结起来,OpenGL项目实战教程需要学习基础知识、选择合适的项目、学习相关技术和工具、编写代码和调试,并不断学习和优化。通过实际的实践和项目经验,可以提升自己的OpenGL编程能力。 ### 回答3: OpenGLOpen Graphics Library)是一个用于渲染二维和维图形的跨平台图形库。它提供了一系列函数用于操作图形、纹理、着色器等,能够实现复杂的图形渲染和动画效果。下面将简要介绍OpenGL项目实战教程OpenGL项目实战教程是一种通过实际项目来学习和实践OpenGL技术的教学方法。它通常基于具体的应用场景,通过逐步完成一个完整的项目,来引导学习者了解和掌握OpenGL的相关知识和技能。 在开始OpenGL项目实战教程之前,学习者需要具备一定的编程基础,如C++或Java等编程语言的基础知识。同时,对于图形学的基本概念和算法也有一定的了解。 在实战教程中,教学者通常会选择具有代表性的项目,例如创建一个简单的3D游戏场景或实现一个基本的图形编辑器等。通过这些项目,学习者可以逐步了解和掌握OpenGL的基本概念、渲染流程、坐标系统、纹理映射、着色器编程等核心内容。 教程通常会结合理论和实践,通过讲解相关概念和技术,例如图形渲染管线、顶点和片段着色器、缓冲区对象等,来引导学习者完成项目的不同阶段。学习者可以借助开源的OpenGL库或框架,例如OpenGL ES、GLEW、GLFW等,加快项目的开发进程。 通过完成OpenGL项目实战教程,学习者可以获得以下几方面的收益。首先,他们可以将理论知识应用于实际项目,更深入地理解和掌握相关技术。其次,他们可以通过项目实战来锻炼编程能力和解决问题的能力。最后,完成的项目还可以作为学习者的作品展示,增强他们的简历或作为个人项目的起点。 总之,OpenGL项目实战教程是一种有效的学习和实践OpenGL技术的教学方法,可以帮助学习者深入了解和掌握OpenGL的相关知识和技能,同时提升他们的编程和解决问题的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值