简体   繁体   English

加载和使用 HLSL 着色器?

[英]Loading and using an HLSL shader?

I've been looking everywhere and all I can find are tutorials on writing the shaders.我一直在寻找所有我能找到的关于编写着色器的教程。 None of them showed me how to incorporate them into my scene.他们都没有向我展示如何将它们合并到我的场景中。

So essentially:所以本质上:

Given an hlsl shader, if I were to have a function called drawTexturedQuad() and I wanted the shader to be applied to the result, how exactly could I do this?给定一个 hlsl 着色器,如果我有一个名为 drawTexturedQuad() 的 function 并且我希望将着色器应用于结果,我该怎么做呢?

Thanks谢谢

ID3DXEffect provides Begin() and BeginPass() methods. ID3DXEffect 提供Begin()BeginPass()方法。 Simply call drawQuad() during that time.在此期间只需调用drawQuad() Any basic tutorial on shaders should show such a sample.任何有关着色器的基本教程都应该显示这样的示例。

Just an additional note- if in doubt, ask MSDN .只是一个附加说明 - 如果有疑问,请询问MSDN

The answer to this is surprisingly complex, and has been getting more difficult as the GPU hardware has been getting more and more powerful.这个问题的答案出奇地复杂,并且随着 GPU 硬件变得越来越强大而变得越来越困难。 The D3DX FX system is an example of all the work that needs to be done, so using that is a good step to just getting things working for short-term usage. D3DX FX 系统是所有需要完成的工作的一个例子,因此使用它是一个很好的步骤,可以让事情为短期使用而工作。

Shaders are code, but they live on another machine from the CPU, so need all of their data marshalled over.着色器是代码,但它们存在于 CPU 的另一台机器上,因此需要对它们的所有数据进行编组。 The fixed parts: basic render states like depth states, stencil states, blending modes, drawing commands;固定部分:基本渲染状态,如深度状态、模板状态、混合模式、绘图命令; are extremely easy to implement.非常容易实现。 The hard part is making a bridge for the programmable parts: shaders, buffers, samplers, and textures.困难的部分是为可编程部分搭建桥梁:着色器、缓冲区、采样器和纹理。

Index buffers just work, since you can only have one, or none in the case of rendering un-indexed geometry.索引缓冲区只是工作,因为在渲染未索引几何体的情况下你只能有一个,或者没有。

Vertex buffers are more or less fairly easy to deal with, since the hardware can be programmed to read the vertex buffers procedurally.顶点缓冲区或多或少相当容易处理,因为可以对硬件进行编程以按程序读取顶点缓冲区。 Your vertex buffers only needs to provide at least as much information as the vertex shader wants to access.您的顶点缓冲区只需要提供至少与顶点着色器想要访问的信息一样多的信息。 Modifications to the shader's vertex input, or the vertex format requiring editing both sides at the same time, and so is reasonably easy to work with.修改着色器的顶点输入,或需要同时编辑两侧的顶点格式,因此相当容易使用。

Samplers and Textures are the next 'easier' of the hard parts to hook: they have a variable name and a rather rigid type.采样器和纹理是下一个“更容易”挂钩的难点:它们有一个变量名和一个相当严格的类型。 For instance, When compiling shader 'foo', texture 'myNormalMap', is assigned texture slot 3. You need to look up (via the reflection APIs) which slot the texture was assigned, and set the texture your engine considers 'myNormalMap' to be to slot 3 at runtime, and of course also use the API to determine if the texture is even needed in the first place.例如,在编译着色器“foo”时,纹理“myNormalMap”被分配纹理槽 3。您需要(通过反射 API)查找纹理被分配的槽,并将引擎认为“myNormalMap”的纹理设置为在运行时到插槽 3,当然也使用 API 来确定是否首先需要纹理。 This is where starting to have naming conventions for shader variables starts to matter, so multiple shaders can be made compatible with the same C++ code.这就是着色器变量的命名约定开始变得重要的地方,因此可以使多个着色器与相同的 C++ 代码兼容。

Constant buffers (or raw shader constants in D3D9) are a lot trickier, especially with a programmable shader framework like you can find in engines like Unreal.常量缓冲区(或 D3D9 中的原始着色器常量)要复杂得多,尤其是对于像 Unreal 这样的引擎中可以找到的可编程着色器框架。 The constants any given shader uses is a subset of the full list, but the C++ side must generally be written as if all of them are needed.任何给定着色器使用的常量都是完整列表的子集,但 C++ 端通常必须像所有这些都需要一样编写。 The reflection APIs again are needed to determine not only which variables are actually referenced in a shader, but where they are located.反射 API 不仅需要确定着色器中实际引用了哪些变量,还需要确定它们所在的位置。 This became a bit more manageable in D3D10 and newer as the cbuffers are structs and less fluid than the D3D9 system which was heavily limited by register count, but it also adds the step of also needing to use the reflection APIs to determine the order of cbuffer bindings (and which cbuffers themselves are also referenced).这在 D3D10 和更新版本中变得更易于管理,因为 cbuffer 是结构体并且比 D3D9 系统流动性差,后者受到寄存器数量的严重限制,但它也增加了还需要使用反射 API 来确定 cbuffer 顺序的步骤绑定(以及哪些 cbuffers 本身也被引用)。

In the end there is one design to make it all work:最后,有一种设计可以使一切正常工作:

Make a class that drives a specific shader archetype.制作一个驱动特定着色器原型的 class。 For each variable this class exposes to a shader (be it a texture, constant buffer, etc), look up in the reflection info if it is used, and find out its location, and set it.对于这个 class 暴露给着色器(可能是纹理、常量缓冲区等)的每个变量,在反射信息中查找它是否被使用,并找出它的位置并设置它。 Keeping this fast, flexible, and extensible is all a difficult challenge.保持这种快速、灵活和可扩展是一项艰巨的挑战。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM