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

利昂·布兰兹

我正在开发一种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。

我是在朝着正确的方向思考还是这是一种完全愚蠢的方法?任何反馈

星光闪耀

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

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

灵活性

您会发现OpenGL在处理属性和制服方面非常灵活,其中DirectX更加注重通过根据渲染通道配置(通常在每个对象/每个帧/每遍基础等。虽然您也可以通过创建微小的块来执行此操作,但这显然会带来不同的性能。

显然,即使在单个API中,也可以通过多种方式进行绑定,甚至缓冲对象或着色器。同样,获取着色器变量名称和绑定点在DirectX中查询也不是那么灵活,并且某些参数需要从代码中进行设置。在Vulkan中,绑定着色器属性和统一更为通用:您可以根据需要完全配置绑定点。

版本控制

另一个主题是与GLSL / HLSL着色版本控制有关的一切:您可能需要为支持较低着色器模型的不同硬件功能编写不同的着色器。如果您要编写独特的着色器,而不是使用uber-shader方法(如果使用此方法,则需要扩展很多),如果它与您的设计联系太紧,并且给定了排列可能是不现实的。

扩展名

可以从着色器中“查询” OpenGL和Vulkan扩展,而其他API(例如DirectX)则需要在代码侧进行设置。仍然,在相同的compute_capability范围内,您可以拥有仅在NVidia上运行的扩展,或者是ARB批准的扩展,而不是CORE的扩展,等等。这确实很混乱,并且在大多数情况下是特定于应用程序的

弃用

API的相当一部分一直不推荐使用。如果您的引擎希望这些功能保持不变,那么这可能会成问题,尤其是当您想处理支持该功能的多个API时。

编译与缓存

现在,大多数API都支持某种形式的脱机编译,以后可以加载。编译需要花费大量时间,因此进行缓存很有意义。由于硬件着色器代码是针对您所拥有的硬件进行唯一编译的,因此您需要针对应用程序运行代码的每个平台执行此练习,无论是应用程序首次使用着色器时,还是以生产中的其他巧妙方式进行管道。在这种情况下,您的文件名将被哈希替换,以便可以从缓存中检索着色器。但这意味着缓存需要一个时间戳,以便它可以检测源着色器的新版本,因为如果着色器源应更改,则需要重建缓存项。等.. :)

长话短说

如果要在任何API中获得最大的灵活性,最终将在引擎中添加一个无用的层,在最佳情况下,该层将简单地复制基础调用。如果您打算使用通用API,则会很快陷入版本故事中,因为扩展,弃用和驱动程序实现支持方面,这些故事在不同API之间完全不同步。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章