LearnOpenGL学习笔记(四)——着色器类编写

更新时间:2023-07-28 06:59:41 阅读: 评论:0

LearnOpenGL学习笔记(四)——着⾊器类编写
之前我们将着⾊器的代码⽤glsl写好之后,保存为字符串指针,然后⽤⼀个函数去编译它,这是⼀种⼿段,对于简单的着⾊器代码可以这样。但当我们针对复杂的着⾊器,我们发现编写、编译、管理着⾊器是⼀件⿇烦事。我们⽤⼀个类将着⾊器的所有编译,链接,管理都放在⼀个⽂件⾥。再将着⾊器源码单独设置成.glsl⽂件⽤来,从⽂件流读取,不再放到c++编译器⾥了。这样主函数就⽐较简洁了。我们建⽴⼀个类shader,将⼀切着⾊器的步骤都在这个类⾥封装了,这样我们在主函数实例化它,我们就直接可以使⽤着⾊器不⽤在意内部的具体情况(从⽂件流读取,编译,链接)。
因为我们是在.h⽂件⾥⾯实现的这些步骤,包括函数的具体实现我们都放到.h⽂件⾥了,所以我们还需要⼀些特殊处理
#ifndef SHADER_H  //先测试x是否被宏定义过
#define SHADER_H    //如果没有宏定义下⾯就宏定义x并编译下⾯的语句
#include <glad/glad.h>; // 包含glad来获取所有的必须OpenGL头⽂件
#include <string>
#include <fstream> //file stream  ,fstream是C++ STL中对⽂件操作的合集,包含了常⽤的所有⽂件操作。
#include <sstream> //字符串流,可以⽀持C风格的串流的输⼊输出操作。
#include <iostream>
#endif    //如果已经定义了则编译#endif后⾯的语句
然后我们可以声明这个类的结构了:
class Shader {
public:
// 程序ID
unsigned int ID;
// 构造器读取并构建着⾊器
Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
// 使⽤/激活程序
void u();
// uniform⼯具函数
void tBool(const std::string &name, bool value) const;
void tInt(const std::string &name, int value) const;
void tFloat(const std::string &name, float value) const;
};
看着⽐较简单,接下来我们对函数的具体实现,分析,⾸先是最重要的构造函数,这⼀个函数⾥⾯,将⼀切编译链接都做完了。构造函数需要传⼊两个参数的⽂件地址(针对vs的.sln⽂件⽬录来说,我们把⽂件放到那⾥,就只需要⼀个名字就可以了),不⽤管第三个,那是⼀个⼏何地址,设为NULL。
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
{ // 1. 从⽂件路径中获取顶点/⽚段着⾊器
//声明⼀些对象,ifstream 的意思是从硬盘到内存的⽂件流对象,这个⽤来存储我们的着⾊器源码,并且对其进⾏处理
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
//保证ifstream对象可以抛出异常,防⽌错误读取,出现故障,即使停⽌。
try
中国教育失败{
// 打开⽂件,这⾥输⼊⽂件地址。
vShaderFile.open(vertexPath);
爆炒五花肉
地球的形状和大小fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;//声明两个读取流对象,⽤来临时存放数据
// 读取⽂件的缓冲内容到数据流中
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭⽂件处理器
vShaderFile.clo();
fShaderFile.clo();
// 转换数据流到string
wps很卡
stringvertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
// if geometry shader path is prent, also load a geometry shader//这⼀段不⽤管。
if (geometryPath != nullptr)
{
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.clo();
geometryCode = gShaderStream.str();
}
}
//如果捕捉到异常,输出⼀些⽂字告诉程序员
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
//声明两个字符串数组指针,⽤来存放从上⾯读下来的源码,⽤于接下来的编译
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
//下⾯的就是编译,链接,删除,这都是类似的了。
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader
unsigned int geometry;
if (geometryPath != nullptr)
{
const char * gShaderCode = geometryCode.c_str();
龙虾养殖
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if (geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
十月革命的意义// delete the shaders as they're linked into our program now and no longer necesry
glDeleteShader(vertex);
glDeleteShader(fragment);
//不管这个
if (geometryPath != nullptr)
glDeleteShader(geometry);
}
好了,现在我们已经成功创造出来了这个类的构造函数,接下来我们设计⼀下⼏个公有函数就好了,它们都很简单。激活程序:
void u() {
glUProgram(ID);
}
// uniform⼯具函数:
我的一天作文500字
鬼斧神工造句
void tBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void tInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void tFloat(const std::string &name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); }好了,这样我们就解决了所有的问题,它让我们的使⽤变得⾮常简单易。
Shader ourShader("path/to/shaders/shader.vs", "path/to/shaders/shader.fs");
... while(...) {
ourShader.u();
ourShader.tFloat("someUniform", 1.0f); DrawStuff();
}

本文发布于:2023-07-28 06:59:41,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1099655.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:编译   读取   链接   声明
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图