Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多渲染API引擎着色器文件管理_C++_Design Patterns_Rendering_Game Engine - Fatal编程技术网

C++ 多渲染API引擎着色器文件管理

C++ 多渲染API引擎着色器文件管理,c++,design-patterns,rendering,game-engine,C++,Design Patterns,Rendering,Game Engine,我正在开发一个3D引擎,旨在支持任何给定图形API的实现。我希望得到您对我计划如何管理着色器文件的反馈: 我考虑创建一个包含3个字符串变量、目录和文件名(顶点和片段)的结构,如下所示: class ShaderFile : public SerializableAsset { std::string nameID; //Identifier std::string directory; std::string vertexName; std::string fra

我正在开发一个3D引擎,旨在支持任何给定图形API的实现。我希望得到您对我计划如何管理着色器文件的反馈:

我考虑创建一个包含3个字符串变量、目录和文件名(顶点和片段)的结构,如下所示:

class ShaderFile : public SerializableAsset
{
    std::string nameID; //Identifier
    std::string directory;
    std::string vertexName;
    std::string fragmentName;
};
用户可以在编辑器中设置这些变量。然后,我的引擎将加载着色器文件,如下所示:

void createShader(RenderAPI api)
{
    ShaderFile shaderFile //Get it from some place
    std::string vertexPath = shaderFile.directory + shader.vertexName + api.name + api.extension;
    std::string fragmentPath = shaderFile.directory + shader.fragmentName + api.name + api.extension;
    //Create shader...
}
这将创建如下内容:Project/Assets/Shaders/standardVulkan.spv


我的想法是正确的还是完全愚蠢的做法?任何反馈

这是一个有趣的想法,我们确实做到了这一点,但我们在过程中发现了一些不容易处理的事情:

如果您深入了解着色器API,尽管它们在纸面上几乎可以提供相同的功能,但它们通常不以相同的方式支持功能,并且必须以不同的方式进行管理。扩展而言,着色器也是如此。在这里,驱动程序实现是关键,在管理内部状态(同步和缓冲区处理)时,有时会有很大的不同

灵活性

您会发现OpenGL处理属性和一致性的方式非常灵活,其中DirectX更专注于根据renderpass配置将它们绑定到块中,从而最大限度地减少对硬件的上传,通常是基于每个对象/每帧/每过程等。。虽然您也可以通过创建小块来实现这一点,但这显然会带来不同的性能

显然,即使在一个API中,也有多种方法进行绑定,甚至缓冲区对象或着色器。此外,在DirectX中查询着色器变量名和绑定点并不是那么灵活,一些参数需要从代码中设置。在Vulkan中,绑定着色器属性和一致性更加通用:您可以根据需要完全配置绑定点

版本控制

另一个主题是与GLSL/HLSL着色版本控制有关的所有内容:您可能需要为支持较低着色器模型的不同硬件功能编写不同的着色器。如果您打算编写独特的着色器,而不打算使用uber着色器方法(如果您使用这种方法,在很大程度上也是如此),那么如果它与您的设计紧密结合,这可能会变得复杂,并且考虑到排列的数量可能是不现实的

扩展

OpenGL和Vulkan扩展可以从着色器中“查询”,而其他API(如DirectX)则需要从代码端进行设置。尽管如此,在相同的compute_功能中,您可以拥有只在NVidia上工作的扩展,或者是ARB批准的但不是核心的扩展,等等。在大多数情况下,这是非常混乱的,并且是特定于应用程序的

弃用

API的相当一部分一直被弃用。如果您的引擎希望这些特性保持不变,这可能会有问题,特别是如果您喜欢处理支持该特性的多个API

编译和缓存

到目前为止,大多数API都支持某种形式的离线编译,可以在以后加载。编译需要相当长的时间,因此缓存是有意义的。由于硬件着色器代码是为您拥有的硬件专门编译的,因此您需要在应用程序第一次需要着色器时,或者在生产管道中以其他巧妙的方式,为代码应该运行的每个平台执行此练习。在这种情况下,您的文件名将替换为哈希,以便可以从缓存中检索着色器。但这意味着缓存需要时间戳,以便能够检测源着色器的新版本,因为如果着色器源发生更改,则需要重建缓存条目。等等:)

长话短说

如果您的目标是在任何API中实现最大的灵活性,那么最终会在引擎中添加一个无用的层,在最好的情况下,它只是复制底层调用。如果您的目标是一个通用的API,那么您很快就会陷入版本故事中,在扩展、弃用和驱动程序实现支持方面,不同API之间完全不同步