7.3Shader文件创建与使用


文档摘要

## 7.3 Shader文件创建与使用 之前项目的Shader代码是写死在 ,不便于修改和更新。 Shader分为Vertex Shader(顶点Shader)和Fragment Shader(片段Shader),现在就将它们分别存放到 和 文件中。 创建Shader文件 创建 和 ,将 中的Shader代码放进去。 加载Shader文件 创建类 负责Shader文件的加载、编译、创建Shader程序、Link。,代码文件是 。 2.1 加载Shader文件 在创建Shader文件时,保证顶点Shader、片段Shader文件名一致,这样只要用 和后缀拼起来就可以将他们都加载到内存。 2.

7.3 Shader文件创建与使用

CLion项目文件位于 samples\mesh_and_material\use_shader_file

之前项目的Shader代码是写死在shader_source.h,不便于修改和更新。
Shader分为Vertex Shader(顶点Shader)和Fragment Shader(片段Shader),现在就将它们分别存放到.vs.fs文件中。

1. 创建Shader文件

创建Unlit.vsUnlit.fs,将shader_source.h中的Shader代码放进去。

2. 加载Shader文件

创建类 Shader负责Shader文件的加载、编译、创建Shader程序、Link。,代码文件是shader.h

2.1 加载Shader文件

在创建Shader文件时,保证顶点Shader、片段Shader文件名一致,这样只要用Shader文件路径 和后缀拼起来就可以将他们都加载到内存。

//加载Shader文件并解析 void Shader::Parse(string shader_name) { shader_name_=shader_name; //组装完整文件路径 string vertex_shader_file_path=shader_name+".vs"; string fragment_shader_file_path=shader_name+".fs"; //读取顶点Shader代码 ifstream vertex_shader_input_file_stream(vertex_shader_file_path); string vertex_shader_source((std::istreambuf_iterator<char>(vertex_shader_input_file_stream)),std::istreambuf_iterator<char>()); //读取片段Shader代码 ifstream fragment_shader_input_file_stream(fragment_shader_file_path); string fragment_shader_source((std::istreambuf_iterator<char>(fragment_shader_input_file_stream)),std::istreambuf_iterator<char>()); CreateGPUProgram(vertex_shader_source.c_str(), fragment_shader_source.c_str()); }

2.2 创建GPUProgram

之前的例子,创建GPUProgram的代码在main.cpp中:

现在将它移动到shader.cpp中:

//编译Shader,创建GPU程序; void Shader::CreateGPUProgram(const char* vertex_shader_text, const char* fragment_shader_text) { //创建顶点Shader unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER); //指定Shader源码 glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); //编译Shader glCompileShader(vertex_shader); ...... ...... }

2.3 缓存与查找

调用Shader::Parse就可以完成Shader文件的加载、编译,并创建GPU Program,不过从之前的例子知道,每执行一次Draw,就是激活一个GPU Program,一个游戏少说也有上百个DrawCall,那么必须要做的就是GPU Program的缓存了。

这里以Shader文件路径做Key,Shader对象实例做Value,缓存起来,并且提供静态接口Find查找或创建Shader:

//查找或创建Shader Shader* Shader::Find(string shader_name) { unordered_map<string,Shader*>::iterator iter=kShaderMap.find(shader_name); if(iter!=kShaderMap.end()) { return iter->second; } Shader* shader=new Shader(); shader->Parse(shader_name); kShaderMap.insert(pair<string,Shader*>(shader_name,shader)); return shader; }

3. 使用Shader

main.cpp中,创建Shader实例对象:

Shader* shader=Shader::Find("../data/shader/unlit"); mvp_location = glGetUniformLocation(shader->gl_program_id(), "u_mvp"); vpos_location = glGetAttribLocation(shader->gl_program_id(), "a_pos"); vcol_location = glGetAttribLocation(shader->gl_program_id(), "a_color"); a_uv_location = glGetAttribLocation(shader->gl_program_id(), "a_uv"); u_diffuse_texture_location= glGetUniformLocation(shader->gl_program_id(), "u_diffuse_texture");

渲染的时候,从Shader实例获取gl_program_id

//指定GPU程序(就是指定顶点着色器、片段着色器) glUseProgram(shader->gl_program_id()); { ...... ...... }

编译运行,测试是否正常。

后续修改Shader代码,就只需要修改Shader文件了,游戏热更新和reload shader都可以安排上。


发布者: 作者: 转发
评论区 (0)
U