Answers:
是的,游戏引擎通常会具有各种不同的着色器。典型的模式是:
在初始化引擎并加载游戏世界时,请准备要用于渲染的所有着色器。“准备”是指将它们加载到内存中,如有必要,对其进行编译,并执行所有ID3D11Device::CreatePixelShader
类似的调用以获取分配的D3D着色器对象并准备就绪。将对象保留在数组或其他数据结构中。
通常,在顶点着色器和旨在共同工作的像素着色器之间将具有一对一的关系。我将它们视为单个对象,即使它确实包含一个顶点着色器和一个像素着色器(也可能包括几何/外壳/域着色器),我也将其称为“着色器”。
在找到要渲染的对象(网格)列表后,每帧均按着色器对其进行排序。这个想法是通过将所有具有给定着色器的对象绘制在一起,以最大程度地减少在帧中切换着色器的次数。这是因为切换着色器是一个有点昂贵的操作(虽然你当然可以做到每帧是几百或上千次,所以它不是真的是贵)。
实际上,您可以更进一步,首先按着色器对材质进行排序,然后对材质进行排序。“材料”是指着色器以及一组纹理和参数的组合。着色器通常具有一些纹理和数值参数(存储在常量缓冲区中),例如,砖材料和沥青材料可能使用相同的着色器代码,但纹理不同。
要进行绘制,只需循环遍历着色器,在中设置每个着色器ID3D11DeviceContext
,设置任何参数(恒定缓冲区,纹理等),然后绘制对象。在伪代码中,包括着色器/材质区别,我提到:
for each shader:
// Set the device context to use this shader
pContext->VSSetShader(shader.pVertexShader);
pContext->PSSetShader(shader.pPixelShader);
for each material that uses this shader:
// Set the device context to use any constant buffers, textures, samplers,
// etc. needed for this material
pContext->VSSetConstantBuffers(...);
pContext->PSSetConstantBuffers(...);
pContext->PSSetShaderResources(...);
pContext->PSSetSamplers(...);
for each mesh that uses this material:
// Set any constant buffers containing parameters specific to the mesh
// (e.g. world matrix)
pContext->VSSetConstantBuffers(...);
// Set the context to use the vertex & index buffers for this mesh
pContext->IASetInputLayout(mesh.pInputLayout);
pContext->IASetVertexBuffers(...);
pContext->IASetIndexBuffer(...);
pContext->IASetPrimitiveTopology(...)
// Draw it
pContext->DrawIndexed(...)
关于管理对象,网格,着色器,输入布局,常量缓冲区等,还有很多要说的,但这足以让您入门。:)