Texture2D txDiffuse : register(t0); SamplerState samLinear : register(s0); cbuffer cbNeverChanges : register(b0) { matrix View; }; cbuffer cbChangeOnResize : register(b1) { matrix Projection; }; cbuffer cbChangesEveryFrame : register(b2) { matrix World; float4 vMeshColor; }; //----------------------------------------------- struct VS_INPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD0; }; struct PS_INPUT { float4 Pos : SV_POSITION; float2 Tex : TEXCOORD0; }; //----------------------------------------------- PS_INPUT VS(VS_INPUT input) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul(input.Pos, World); output.Pos = mul(output.Pos, View); output.Pos = mul(output.Pos, Projection); output.Tex = input.Tex; return output; } float4 PS(PS_INPUT input) : SV_Target { return txDiffuse.Sample(samLinear, input.Tex) * vMeshColor; }一般在定义常量时,根据数据被修改的频率,将修改频率不同的数据定义在不同的cbuffer中,这样可以提升效率。如上所示的HLSL代码,定义了以下几个常量:
matrix View; // 几乎没有修改
matrix Projection; // 修改频繁很小
matrix World; // 修改频繁较大
float4 vMeshColor; // 修改频繁较大
以下是C++中更新这几个变量的逻辑。主要有三个函数:初始化、更新、使用
ID3D11Buffer* g_pCBNeverChanges = nullptr; ID3D11Buffer* g_pCBChangeOnResize = nullptr; ID3D11Buffer* g_pCBChangesEveryFrame = nullptr; struct CBNeverChanges { XMMATRIX mView; }; struct CBChangeOnResize { XMMATRIX mProjection; }; struct CBChangesEveryFrame { XMMATRIX mWorld; XMFLOAT4 vMeshColor; }; void InitConstantBuffer() { D3D11_BUFFER_DESC bd; ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.ByteWidth = sizeof(CBNeverChanges); g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBNeverChanges); bd.ByteWidth = sizeof(CBChangeOnResize); g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBChangeOnResize); bd.ByteWidth = sizeof(CBChangesEveryFrame); g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBChangesEveryFrame); } void UpdateConstantBuffer() { CBNeverChanges cbNeverChanges; cbNeverChanges.mView = ...; // 赋值 g_pD3DDeviceContext->UpdateSubresource(g_pCBNeverChanges, 0, nullptr, &cbNeverChanges, 0, 0); CBChangeOnResize cbChangesOnResize; cbChangesOnResize.mProjection = ...; // 赋值 g_pD3DDeviceContext->UpdateSubresource(g_pCBChangeOnResize, 0, nullptr, &cbChangesOnResize, 0, 0); CBChangesEveryFrame cb; cb.mWorld = ...; // 赋值 cb.vMeshColor = ...; // 赋值 g_pD3DDeviceContext->UpdateSubresource(g_pCBChangesEveryFrame, 0, nullptr, &cb, 0, 0); } void Render() { // clear g_pD3DDeviceContext->ClearRenderTargetView(g_pRenderTargetView, Colors::MidnightBlue); g_pD3DDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0); // render g_pD3DDeviceContext->VSSetShader(g_pVertexShader, nullptr, 0); g_pD3DDeviceContext->VSSetConstantBuffers(0, 1, &g_pCBNeverChanges); g_pD3DDeviceContext->VSSetConstantBuffers(1, 1, &g_pCBChangeOnResize); g_pD3DDeviceContext->VSSetConstantBuffers(2, 1, &g_pCBChangesEveryFrame); // 顶点着色器用到了全部三个常量区,所以需要设置3个常量区 g_pD3DDeviceContext->PSSetShader(g_pPixelShader, nullptr, 0); g_pD3DDeviceContext->PSSetConstantBuffers(2, 1, &g_pCBChangesEveryFrame); // 像素着色器只用到了第三个常量区,所以只需要设置索引为2的常量区 g_pD3DDeviceContext->PSSetShaderResources(0, 1, &g_pTextureRV); // 对应HLSL的 Texture2D txDiffuse g_pD3DDeviceContext->PSSetSamplers(0, 1, &g_pSamplerLinear); // 对应HLSL的 SamplerState samLinear g_pD3DDeviceContext->DrawIndexed(36, 0, 0); g_pSwapChain->Present(0, 0); }