当前位置: 首页 > news >正文

【OpenGL学习】(五)自定义着色器类

文章目录

  • 【OpenGL学习】(五)自定义着色器类
    • 着色器类
    • 插值着色
    • 统一着色

【OpenGL学习】(五)自定义着色器类

项目结构:
在这里插入图片描述

着色器类

// shader_s.h
#ifndef SHADER_H
#define SHADER_H#include <glad/glad.h>#include <string>
#include <fstream>
#include <sstream>
#include <iostream>class Shader
{
public:unsigned int ID; // 存储着色器程序的唯一标识符// 参数 vertexPath - 顶点着色器文件的路径// 参数 fragmentPath - 片段着色器文件的路径Shader(const char* vertexPath, const char* fragmentPath){// 1. 从文件路径中获取顶点/片段着色器源代码std::string vertexCode; // 存储顶点着色器源代码的字符串std::string fragmentCode; // 存储片段着色器源代码的字符串std::ifstream vShaderFile; // 用于读取顶点着色器文件的输入流std::ifstream fShaderFile; // 用于读取片段着色器文件的输入流// 确保ifstream对象可以抛出异常:vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);try{// 打开文件vShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// 将文件内容读入流中vShaderStream << vShaderFile.rdbuf(); // 读取顶点着色器文件内容fShaderStream << fShaderFile.rdbuf(); // 读取片段着色器文件内容// 关闭文件句柄vShaderFile.close();fShaderFile.close();// 将流转换为字符串vertexCode = vShaderStream.str(); // 将顶点着色器流转换为字符串fragmentCode = fShaderStream.str(); // 将片段着色器流转换为字符串}catch (std::ifstream::failure& e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;}const char* vShaderCode = vertexCode.c_str(); // 转换为C风格字符串的顶点着色器代码const char* fShaderCode = fragmentCode.c_str(); // 转换为C风格字符串的片段着色器代码// 2. 编译着色器unsigned int vertex, fragment;// 顶点着色器vertex = glCreateShader(GL_VERTEX_SHADER); // 创建顶点着色器对象glShaderSource(vertex, 1, &vShaderCode, NULL); // 将顶点着色器源代码附加到着色器对象glCompileShader(vertex); // 编译顶点着色器checkCompileErrors(vertex, "VERTEX"); // 检查顶点着色器编译错误// 片段着色器fragment = glCreateShader(GL_FRAGMENT_SHADER); // 创建片段着色器对象glShaderSource(fragment, 1, &fShaderCode, NULL); // 将片段着色器源代码附加到着色器对象glCompileShader(fragment); // 编译片段着色器checkCompileErrors(fragment, "FRAGMENT"); // 检查片段着色器编译错误// 着色器程序ID = glCreateProgram(); // 创建着色器程序对象glAttachShader(ID, vertex); // 将顶点着色器附加到程序glAttachShader(ID, fragment); // 将片段着色器附加到程序glLinkProgram(ID); // 链接着色器程序checkCompileErrors(ID, "PROGRAM"); // 检查着色器程序链接错误// 删除着色器,因为它们已经链接到我们的程序中,不再需要glDeleteShader(vertex); // 删除顶点着色器对象glDeleteShader(fragment); // 删除片段着色器对象}// 激活着色器// 使用当前着色器程序void use(){glUseProgram(ID); // 激活着色器程序}// setVec4// 参数 name - uniform变量的名称// 参数 v0, v1, v2, v3 - 要设置的四个浮点数值void setVec4(const std::string& name, float v0, float v1, float v2, float v3) const{glUniform4f(glGetUniformLocation(ID, name.c_str()), v0, v1, v2, v3); // 设置uniform vec4值}
private:// checkCompileErrors:用于检查着色器编译/链接错误。// 参数 shader - 要检查的着色器对象或程序对象// 参数 type - 着色器或程序的类型void checkCompileErrors(unsigned int shader, std::string type){int success; // 用于存储编译或链接成功与否的标志char infoLog[1024]; // 用于存储错误信息的缓冲区if (type != "PROGRAM"){glGetShaderiv(shader, GL_COMPILE_STATUS, &success); // 获取着色器编译状态if (!success){glGetShaderInfoLog(shader, 1024, NULL, infoLog); // 获取着色器编译错误信息std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}else{glGetProgramiv(shader, GL_LINK_STATUS, &success); // 获取程序链接状态if (!success){glGetProgramInfoLog(shader, 1024, NULL, infoLog); // 获取程序链接错误信息std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}}
};
#endif

插值着色

顶点着色器:

// shader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;out vec3 ourColor;void main()
{gl_Position = vec4(aPos, 1.0);ourColor = aColor;
}

片段着色器:

// shader.fs
#version 330 core
out vec4 FragColor;in vec3 ourColor;void main()
{FragColor = vec4(ourColor, 1.0f);
}

主函数实现:

// Application.cpp
#include <glad/glad.h>     
#include <GLFW/glfw3.h>   
#include <shader_s.h>     
#include <iostream>    // 函数声明
void framebuffer_size_callback(GLFWwindow* window, int width, int height); // 窗口大小变化时的回调函数
void processInput(GLFWwindow* window); // 处理用户输入// 设置窗口的宽度和高度
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{// 初始化GLFWglfwInit();// 配置GLFWglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 设置OpenGL的主版本号为3glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 设置OpenGL的次版本号为3glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心模式#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 在macOS上启用向前兼容
#endif// 创建GLFW窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate(); // 如果窗口创建失败,终止GLFWreturn -1;}glfwMakeContextCurrent(window); // 将窗口的上下文设置为当前线程的上下文glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // 设置窗口大小变化的回调函数// 初始化GLAD,加载OpenGL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// !!!创建并编译着色器程序Shader ourShader("shader.vs", "shader.fs"); // 使用指定的顶点着色器和片段着色器文件创建着色器对象// 设置顶点数据(和缓冲区)并配置顶点属性float vertices[] = {// positions         // colors0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // 右下角,红色-0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // 左下角,绿色0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // 顶部,蓝色};unsigned int VBO, VAO; // 定义顶点缓冲对象和顶点数组对象glGenVertexArrays(1, &VAO); // 生成一个顶点数组对象glGenBuffers(1, &VBO); // 生成一个顶点缓冲对象// 绑定顶点数组对象,然后绑定和设置顶点缓冲,最后配置顶点属性glBindVertexArray(VAO); // 绑定顶点数组对象glBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定顶点缓冲对象glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据复制到缓冲中// 位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); // 指定顶点属性的格式glEnableVertexAttribArray(0); // 启用顶点属性数组// 颜色属性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); // 指定颜色属性的格式glEnableVertexAttribArray(1); // 启用颜色属性数组// 通常不需要解绑顶点数组对象,因为修改其他顶点数组对象时需要再次绑定// glBindVertexArray(0);// 渲染循环while (!glfwWindowShouldClose(window)){// 处理输入processInput(window);// 渲染glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清除颜色glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲// 渲染三角形ourShader.use(); //  !!!使用着色器程序glBindVertexArray(VAO); // 绑定顶点数组对象glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形// 交换缓冲并查询IO事件glfwSwapBuffers(window); // 交换颜色缓冲glfwPollEvents(); // 检查并调用事件}// 可选:释放所有资源glDeleteVertexArrays(1, &VAO); // 删除顶点数组对象glDeleteBuffers(1, &VBO); // 删除顶点缓冲对象// 终止GLFW,清除所有GLFW资源glfwTerminate();return 0;
}// 处理输入:查询GLFW是否有按键被按下/释放,并执行相应的操作
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) // 如果按下ESC键glfwSetWindowShouldClose(window, true); // 关闭窗口
}// 窗口大小变化时的回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height); // 调整视口大小以匹配窗口的新尺寸
}

统一着色

顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;void main()
{gl_Position = vec4(aPos, 1.0);
}

片段着色器:

#version 330 core
out vec4 FragColor;
uniform vec4 ourColor; // 用于设置颜色的uniform变量void main()
{FragColor = ourColor; // 使用uniform颜色
}

主函数:

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <shader_s.h>
#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endifGLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}Shader ourShader("shader.vs", "shader.fs");float vertices[] = {// positions0.5f, -0.5f, 0.0f,  // bottom right-0.5f, -0.5f, 0.0f,  // bottom left0.0f,  0.5f, 0.0f   // top };unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);while (!glfwWindowShouldClose(window)){processInput(window);glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);ourShader.use();// 设置uniform颜色为绿色ourShader.setVec4("ourColor", 0.0f, 1.0f, 0.0f, 1.0f);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glfwTerminate();return 0;
}void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}

在这里插入图片描述

相关文章:

  • 【PmHub面试篇】性能监控与分布式追踪利器Skywalking面试专题分析
  • BugKu Web渗透之需要管理员
  • DDD架构实战 充血模型 电商订单
  • Qt客户端技巧 -- 窗口美化 -- 圆角窗口
  • 当下AI智能硬件方案浅谈
  • JS-- for...in和for...of
  • pandas随笔
  • Google机器学习实践指南(机器学习模型泛化能力)
  • 博弈论概述
  • RockyLinux9.6搭建k8s集群
  • ComfyUI 局部重绘工作流示例
  • (nice!!!)(LeetCode每日一题)2434. 使用机器人打印字典序最小的字符串(贪心+栈)
  • 破壁焕新能:DeviceNET转EtherNet/IP网关赋能烟草智能制造跃迁
  • 外卖大战背后的创始人IP智慧:差异化、护城河与心智占领
  • DAY 23 pipeline管道
  • C#使用MindFusion.Diagramming框架绘制流程图(1):基础类型
  • FART 脱壳某大厂 App + CodeItem 修复 dex + 反编译还原源码
  • maven私服
  • 基于KNN算法的入侵检测模型设计与实现【源码+文档】
  • C++.OpenGL (5/64)变换(Transformation)
  • 路由器做网站主机要备案吗/网络营销公司名字
  • 香河住房和建设局网站/公关负面处理公司
  • 天津装修公司排名前十名/网站seo推广营销
  • 苏州建设网站公司/松原头条新闻今日新闻最新
  • python不用框架做动态网站/seo外包大型公司
  • 有什么网站是可以做动态图的/职业技能培训班