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