3.4.2顶点着色器状态配置
作为可编程着色器阶段,顶点着色器实现通用着色器核心功能。这意味着它提供了一组标准的资源接口方法,允许应用程序向着色器程序提供对所需资源的访问。与所有管道操作一样,所有可以更改顶点着色器阶段状态的方法都属于ID3DllDeviceContext接口。我们将查看这些可用资源中的每一个,并了解它们在顶点着色器阶段的上下文中是如何使用的。
着色器可配置:
- 着色器程序配置
- 常量绘冲区
- 着色器资源视图
- 采样器
着色器程序
顶点着色器阶段的第一个状态,也是最重要的状态,是着色器程序本身。第6章详细描述了编译着色器并从中创建着色器对象的过程,因此我们将在这里假设编译的着色器已用于创建有效的顶点着色器对象。应用程序通常会创建多个顶点着色器对象以用于渲染各种对象。
//g_VS来源于对着色器代码编译后的字节流
UINT Size = ARRAYSIZE(g_VS);
ID3D11VertexShaderr* m_VertexShader
//使用该字节流创建顶点着色器
hr = m_Device->CreateVertexShader(g_VS, Size, nullptr, &m_VertexShader);
//设置顶点着色器
m_pCorttext->VSSetShader(m_VertexShader, 0, 0 )
设置所需着色器对象的方法需要三个参数。第一个是指向要绑定到场景的着色器对象的指针。第二和第三参数用于传递要在着色器程序中使用的着色器类实例的阵列。这些类实例是可用于为着色器程序的一部分提供外部对象的对象,旨在减少支持各种类似渲染场景所需的单个着色器对象的数量。还有相应的ID3DllDeviceContext::VSGetShader方法,可用于检索当前绑定到顶点着色器阶段的着色器和类实例对象。这对于读取现有着色器对象设置非常有用,以便在执行临时操作后恢复该设置。
void VSSetShader(
[in, optional] ID3D11VertexShader *pVertexShader,
[in, optional] ID3D11ClassInstance * const *ppClassInstances,
UINT NumClassInstances
);
常理缓冲区
应用程序可以提供给顶点着色器程序的下一个配置是常量缓冲区的阵列。第2章详细介绍了常数缓冲器。这些基本上是应用程序加载的缓冲区资源,其中包含着色器程序可用的参数,着色器程序可以直接在HLSL代码中使用数据。这用于向着色器程序传递参数,这些参数在整个管道执行过程中保持不变,因此命名为常量缓冲区。第2章也详细描述了用数据填充常量缓冲区的过程,因此我们将在这里重点讨论如何将这些资源绑定到顶点着色器阶段。
清单3.9显示了如何将一个或多个常量缓冲区绑定到顶点着色器阶段。
ID3DllBuffer* cbuffePS[D3Dll_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
// Fill each element of the array with buffers here
pContext->VSSetConstantBuffers( 0, count, cbuffers );
函数声明:
void VSSetConstantBuffers(
[in] UINT StartSlot,
[in] UINT NumBuffers,
[in, optional] ID3D11Buffer * const *ppConstantBuffers
);
清单3.9展示了如何使用单个设备上下文方法设置多个常量缓冲区。
事实上,这个例子展示了如何设置所有可用的常量缓冲区插槽。如果ID3D11Buffer数组的所有元素都被初始化为NULL,这可能是一种有利的技术。然后,当NULL值被绑定到它的位置时,以前附加到此阶段的任何常量缓冲区都会自动分离。
图3.14描述了在这种“完整”状态设置前后顶点着色器中的常量缓冲区槽。也可以使用相应的ID3D11DeviceContext::VSGetConstant Buffers方法来检索当前在顶点着色器阶段中设置的常量缓冲区指针数组。同样,这对于在执行临时操作后恢复现有设置非常有用。
着色器资源视图
为了使顶点着色器程序能够访问其可用的各种类型的只读资源,这些资源必须绑定到具有着色器资源视图的顶点着色器阶段。缓冲区资源和纹理资源都以完全相同的方式绑定到管道,使用ID3D11DeviceContext::VSSetShaderResources方法。与常量缓冲区一样,可以使用相同的方法调用同时设置一个或多个着色器资源视图。
ID3DllShaderResourceView*
ShaderResourceViews[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
// F i l l the array with the desired resource views...
pContext->VSSetShaderResources(start, count, ShaderResourceViews );
Listing 3.10. Binding an array of shader resource views to the vertex shader stage.
着色器资源视图阵列的操作方式与为常量缓冲区描述的方式大致相同。一旦在其中一个插槽中设置了着色器资源视图,它将保持绑定在此位置,直到被另一个着色器资源视图或NULL指针替换为止。在管道执行之间用NULL清除所有未使用的着色器资源视图的技术在应用于资源时更为重要。
如果GPU动态生成的资源在另一个渲染过程中用作着色器资源,则在第一个过程中,它首先由管道写入,然后在第二个过程中在着色器程序中读取。对资源的写入使用渲染目标视图或无序访问视图来完成,而读取使用着色器资源视图来执行。如果某个资源绑定为使用着色器资源视图进行读取,并且错误地保留为绑定到顶点着色器阶段,则任何绑定资源进行写入的尝试都将产生错误,因为多个视图无法同时读取和写入资源。这种情况如图3.15所示。确保这种情况不会发生的最简单方法是,每次为新渲染效果配置管道时,从顶点着色器阶段清除所有不需要的着色器资源视图.
采样器
应用程序可以提供给顶点着色器阶段的最终配置是采样器对象。当从内存中读取纹理时,采样器能够对纹理执行各种类型的过滤。这通常会显著提高采样值的性能和质量,因为GPU通常具有专门用于加速这一过程的额外专用硬件。清单3.11演示了ID3DllSamplerState实例是如何绑定到管道的。再一次,我们看到了一种熟悉的方法,即同时设置一个采样器状态数组,以减少配置渲染管道所需的与API的交互次数。
ID3DllSamplerState * SamplerStates[D3D11_C0MMONSHADER_SAMPLER_SLOT_C0UNT];
pContext->VSSetSamplers(start , count, SamplerStates );
Listing 3.11. Binding an array of sampler state objects to the vertex shader stag
总结
总的来说,我们可以将这四种配置组合在一起,并将它们视为可用的顶点着色器阶段状态。配置顶点着色器需要合适的着色器程序,以及着色器程序中所需的所有常量缓冲区、着色器资源和采样器。由于每个顶点着色器程序可能具有显著不同的用途和要求,因此这些状态可能有许多不同的组合。