部分更新 D3D11 常量缓冲区

Posted

技术标签:

【中文标题】部分更新 D3D11 常量缓冲区【英文标题】:Partially updating D3D11 constant buffer 【发布时间】:2022-01-13 20:17:21 【问题描述】:

在业余时间,我正在使用 D3D11 开发 3D 引擎。为了获得 3D 效果,我在 HLSL 着色器中使用了典型的模型视图投影矩阵乘法。这些矩阵被上传到 d3d11 常量缓冲区。投影矩阵仅在调整视口大小时更改,但模型和视图矩阵可以在每帧的基础上更改(当模型或相机移动时)。矩阵中的这些更改必须上传到相同的常量缓冲区才能在着色器中使用。上传这些更改时,投影矩阵(通常)没有改变,所以我不想重新上传这个矩阵。所以简而言之,我需要通过仅更新缓冲区中的特定部分(偏移量)来部分更新我的常量缓冲区。

在 openGL 中,我们有统一的缓冲区,这些工作(我认为)与 d3d11 常量缓冲区的工作方式相同。但是,如果要更新统一缓冲区的特定部分,可以使用 openGL 函数 glBufferSubData。我尝试在 D3D11 中寻找类似的方法来执行此操作,但我没有找到任何东西。我确实找到了有类似问题的人,但他使用的是 D3D11.1。 原帖链接:How to partially update constant buffer in DirectX 11.1。也有人说,在D3D11中,如果要更改特定部分,则需要将所有数据上传到常量缓冲区中。但这可能会导致在 CPU 端 (RAM) 上保留我的缓冲区的整个副本。一定有更好的方法吧?

tldr;如何在特定偏移量上更新我的 d3d11 常量缓冲区?

【问题讨论】:

【参考方案1】:

您有多种管理方式。

最简单的方法是为每个更新速率创建一个常量缓冲区(因此您将拥有一个用于世界矩阵的缓冲区,每个对象都会发生变化,一个用于每帧更新一次的视图,另一个用于非常零星更新的投影。

也就是说,我从来没有发现分割视图和投影矩阵的好处是什么(我的意思是我们说每帧有 64 字节的额外数据更新,这真的没什么,特别是考虑到常量缓冲区在 256字节边界)。

如果您将开始添加阴影贴图,则更是如此(如果您使用平截头体拟合您的阴影相机投影矩阵可以改变每一帧)。

此外,如果您计划稍后添加其他后期效果(如 ao、景深...),您还需要为相机添加额外数据(位置、视图逆向、视图投影逆向、投影逆向),所以每帧更新一次所有相机数据通常更有益(我通常使用保留的 cbuffer 插槽作为相机缓冲区,所以我不必一直重新绑定它)。

【讨论】:

因为我确实计划最终添加阴影贴图以及一些后期处理效果,所以将这些矩阵分离到单独的常量缓冲区中是一个更好的主意。感谢您的帮助!【参考方案2】:

为什么没有多个常量缓冲区?这样一来,您就可以拥有一个很少更改的内容,而其他内容可以随每一帧而更改。我很确定我已经在一些示例中看到了它(尽管我没有去寻找)。

【讨论】:

我可以实现它以使用多个常量缓冲区。这可能不是一个糟糕的解决方案,感谢您的帮助!

以上是关于部分更新 D3D11 常量缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

HLSL 统一变量与常量缓冲区

如何从 Direct3d11 中的顶点缓冲区读取顶点

如何在 webgl 中使用帧缓冲目标?

DirectX11--深入理解Effects11使用着色器反射机制(Shader Reflection)实现一个复杂Effects框架

C++ 协议缓冲区:常量表达式中的临时非文字类型 'google::protobuf::internal::CallOnInitializedMutex <std::mutex>'

如何通过在 glsl 中注册来设置着色器常量?