【问题标题】:DirectX 11 Rendering Pipeline Using Different Shader Programs使用不同着色器程序的 DirectX 11 渲染管线
【发布时间】:2017-09-26 17:40:07
【问题描述】:

我目前正在阅读 Practical Rendering and Computation with Direct3D 11。对于 DirectX/OpenGL 经验最少的人,我发现它非常有用,并给了我一些很好的指导。一切都说得通,而且看起来很简单(尽管非常沉重)。

但是,我目前正在阅读第 3 章(130 多页),但我仍然对一件简单的事情感到困惑。

着色器程序,例如...如果您希望一些资源使用特定的着色器程序,而另一个使用其他着色器程序怎么办。或者,是否每个资源都得到相同的处理?此处的资源,请参阅顶点/索引数据,或 Texture1/2/3,或者...如果我有一个正在渲染的模型并希望它使用管道中的特定着色器程序。

显然,必须有某种方式让一些输入沿着不同的路径传输到不同的渲染结果。

但到目前为止,我还没有在书中看到它(也许我会再读100页)。

抱歉,如果这个问题已经在某个地方,不太清楚如何构建谷歌搜索这样的东西。

编辑:为了清晰

假设我有一个名为 ShaderA_vs.hlsl 的顶点着色器和另一个名为 ShaderB_vs.hlsl 的顶点着色器。现在,我加载了两个对象模型:ModelA 和 ModelB。我希望 ModelA 使用 ShaderA_vs,ModelB 使用 ShaderB_vs

【问题讨论】:

    标签: shader directx-11


    【解决方案1】:

    GPU 着色器编程实际上有两种不同的途径:

    可编程渲染

    此模型是在 Direct3D 8.1 中引入的,它是“变换和光照”部分和“纹理混合级联”的旧固定功能旧模型的演变。 Vertex Shader 是一个替代“Transform & Light”的着色器程序,Pixel Shader 替代了“Texture blend cascade”。

    要渲染单个对象(点、线或三角形),您需要设置一个顶点着色器,每个点运行一次,作为顶点缓冲区中的原始数据提供(并且可能由索引缓冲区索引)。然后,硬件光栅化器为对象在 2D 屏幕上绘制时触摸的每个像素执行像素着色器。对于着色器和相关状态的特定组合,您可以一次绘制单个像素或 40 亿个三角形。

    如果您想更改任何状态或着色器程序本身的任何方面,则必须提交新的绘图。您可以在每次绘制之间更改部分或全部状态,并且在某些情况下,您可能需要显式清除某些状态以避免来自调试层的验证警告。

    整个场景的高效状态管理是一项挑战,因此请务必避免假设状态、依赖未设置的默认状态以及假设状态在Present 调用之间逐帧持续存在。

    即使在现代 DirectX 管道中,所有装饰包括硬件镶嵌、几何着色器和基于物理的逐像素照明,都是对同一基本概念的扩展。

    对于图形渲染,这通常是一个很好的概念模型,并且可以很好地映射到习惯于在旧的 T&L + TextureBlending 模型中思考的人们。它还可以通过多种方式进行扩展,并在关键点非常有效地使用固定功能硬件来完成一般计算中昂贵的事情,例如多边形扫描线转换、z 缓冲区深度剔除和 alpha 混合。

    计算

    人们使用以前的模型用传统的可编程管道做有趣的非图形工作,你根本不关心光栅化或顶点着色器在做什么,你只需要在整体上绘制一个大矩形渲染目标,然后你在像素着色器中做了很多事情。然后,您将生成的渲染目标视为某种“通用缓冲区”。

    这里的问题是,将问题映射到这个“绘图但做其他事情”的模型有点痛苦,这就是我们得到“计算着色器”的地方(DirectX 称之为 DirectCompute)。在此模型中,您根本不使用顶点缓冲区、索引缓冲区、点/线/三角形、光栅化器或纹理混合。您只需运行一个写出缓冲区的着色器。您可以通过Dispatch 控制直接运行多少个着色器实例。

    顶点着色器、像素着色器、计算着色器等都可以做基本相同的事情,即查找部分资源(纹理或被视为通用缓冲区),对它们进行计算,并将结果写入其他一些视频内存.由于隐含的输入,着色器的顶级调用有所不同,但仅此而已。

    计算着色器可以做的一件事是其他模型的着色器无法做到的,那就是通过少量共享内存与其他着色器实例进行(有限的)通信。这打破了您从以前的模型中获得的极其强大的多线程优势,但使得解决某些问题变得更加容易。在不造成重大停顿的情况下,这件事很难做到,而且您通常需要手动计算所有同步才能获得有效的结果。

    我应该提到,CUDA 所做的还有第三条路径,它是一个隐藏所有低级着色器内容并伪装成 C 的系统。它仍然在做与“计算”相同的事情封面。

    【讨论】:

    • 谢谢,但我认为这不能回答我的问题。对不起,如果我不是很清楚。假设我有一个名为 ShaderA_vs.hlsl 的顶点着色器和另一个名为 ShaderB_vs.hlsl 的顶点着色器。现在,我加载了两个对象模型:ModelA 和 ModelB。我希望 ModelA 使用 ShaderA_vs,ModelB 使用 ShaderB_vs。
    • 您设置了 VS ShaderA_vs.hlsl(和兼容的像素着色器)。您为 ModelA 提交了一个或多个 DrawIndexed 调用。然后设置 VS ShaderB_vs.hlsl(和兼容的像素着色器)。您为 ModelB 提交了一个或多个 DrawIndexed 调用。与“子网格”一致的典型模型,其中每个子网格都是状态和着色器的单一组合。更高级的渲染系统按材质对所有子网格进行排序,因此它们将所有“材质 1”的东西一起绘制,然后是“材质 2”,等等——在绘制任何使用 alpha 混合的东西之前先绘制不透明的东西很重要。
    • 好的!可以根据 DrawIndex 设置和共享的资源(在 GPU 上)如何?工作流程是:设置所有资源(纹理和其他东西),设置着色器,提交模型。对于下一个模型,设置另一个着色器,然后提交!对于非常好的工作流程,是否为每个对象分组所有相同的材质/着色器,以便您只设置一次资源?
    • 所有状态都在Draw 调用之间保留——尽管您应该小心假设默认状态或在Present 之后该状态在帧之间持续存在。如果您想保持相同的绑定,请不要更改任何内容。如果您想要不同的,请重新绑定。如果你需要清除绑定,你也必须这样做
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多