工程GIT地址:https://gitee.com/yaksue/yaksue-graphics
无用的前言
看了下提交记录,这个工程上次更新已经是一年以前了。最近想想,还是应该回来再继续学学,暂且不论是否对工作有帮助,我在这个工程上获得的愉悦感相比学其他东西是更大的。
所以今天又把工程拉了下来。由于最近重装了系统,所以要重新配置下环境。但说是配置,其实也很简单。可能是因为装了最新的系统,所以D3D11和D3D12不需要额外的操作就能跑了。而OpenGL本来也就是借助Glad,也不需要配置。唯一要做的就是安装一个VulkanSDK就行了(安装时会添加环境变量,而工程里会通过环境变量找到VulkanSDK的库)。
刚回坑,就先搞个相对简单的问题好了(搞完后发现也挺多坑的。。):
目标
由于我以后可能需要定义些通用的shader函数,自然想要将他们放入单独的shader文件并由其他shader文件include它们。
这在hlsl中会很容易,但是glsl默认状态下并不支持。本篇目标是学习如何解决这个问题,最终让工程里D3D11、D3D12、OpenGL、Vulkan都可以在shader中使用 include。
1. D3D11
由于hlsl直接就支持,所以直接就能使用。
我将当前一些通用的函数放入同目录的"Utils.hlsl"
文件中后,使用时直接include就行:
#include "Utils.hlsl"
2. D3D12
本以为D3D12也是直接支持,但是遇到了一个小错误。
编译shader时显示的错误如下:
我在这里找到了解决方法:
DX11开发报错error X1505: No include handler specified, can’t perform a #include._MaloFleur的博客-CSDN博客
即编译shader时指定D3D_COMPILE_STANDARD_FILE_INCLUDE
:
随后就能正常使用了。
3. OpenGL
相对来说,glsl默认是不支持的。
这里有对于这个问题做讨论:
因此问题变得复杂了些,如果你要使用include的话,你需要这么做:
首先,你需要GL_ARB_shading_language_include
这个扩展。这在当时使用glad得到的文件中没有包含,所以我需要拐回头再使用一次glad,将生成的文件替换到工程里:(这里也有相关的讨论:LearnGL - 12 - GLSL include - GL_ARB_shading_language_include (Extensions扩展) - 各种踩坑_Jave.Lin的博客-CSDN博客)
然后,在C++中时,你需要事先把想要include的文件加入,我这里在初始化阶段加入了下面的代码:
(我在这里找到了些参考)
//include时的文件名:
const char* glslName = "/Utils.glsl";
//文件的内容:
const GLchar* glslContent = ReadShader("shaders/glsl/Utils.glsl");
//将文件名和文件内容对应起来:
glNamedStringARB(GL_SHADER_INCLUDE_ARB, strlen(glslName), glslName, strlen(glslContent), glslContent);
通过这段代码,Utils.glsl
文件中的内容与"/Utils.glsl"
这个名字对应了起来,然后在glsl文件中,就可以include了:(还要启用GL_ARB_shading_language_include
)
#extension GL_ARB_shading_language_include : require
#include "/Utils.glsl"
而这么做的缺点,也在这里有讨论:
4. Vulkan
本以为Vulkan也需要费事,但实际是,并不需要做任何操作。参考这里的讨论,使用 glslc 编译时已经具备了include功能了!
5. 让Vulkan和OpenGL可使用相同的glsl文件
虽然Vulkan省事了,但由于它现在和OpenGL使用的是同一个glsl文件,所以会遇到问题,它提示不支持 GL_ARB_shading_language_include:(也可以理解,毕竟它也不需要)
error: ‘#extension’ : extension not supported: GL_ARB_shading_language_include
所以我最后决定,让OpenGL编译shader时在C++中通过字符串编辑加入这个GL_ARB_shading_language_include
,这样就不影响Vulkan了。
不过这里还遇到个问题就是,#version
必须在第一行且无法声明两次:
error C0204: version directive must be first statement and may not be repeated
所以,我不能直接加这个GL_ARB_shading_language_include
,而是找到#version
然后在它之后加。具体代码实现如下:
// 这里在C++中加上OpenGL自己需要的拓展(由于Vulkan不需要且不支持,所以不能直接在glsl文件中写上)
// 另外要注意,#version必须永远是第一行,所以要找到他并且在其后面添加内容
std::string str_source = source; //原始shader文件
std::string str_version = "#version 450";
str_source.replace(str_source.find(str_version), str_version.length(), "#version 450\n#extension GL_ARB_shading_language_include : require\n");
总结
hlsl直接支持。我这里D3D12虽然直接使用遇到了问题,但也可以通过在编译shader时指定D3D_COMPILE_STANDARD_FILE_INCLUDE
来解决。
Vulkan 由于使用了 glslc 编译shader,也是支持include的。
OpenGL最费事,要使用GL_ARB_shading_language_include
功能。需要提前读取被include的shader文件。另外,我这里为了让Vulkan和OpenGL可使用相同的glsl文件,我选择让OpenGL编译shader在C++中加入GL_ARB_shading_language_include
。
至此,四个图形API都可以使用include了。
其他:显示D3D编译shader文件时遇到的错误信息
之前编译shader时并不会显示错误信息,今天为了定位遇到的D3D12的问题也改了下代码,即编译时传入一个ID3DBlob
用于容纳错误的信息,如果出现错误则显示它: