- A constant buffer is a way to pass data from your C++ code to the shader.
- For Vertex Shaders, we usually want it to know the World, View, and Projection matrix for it to translate the world position to the screen position.
- For Pixel Shaders, it is useful for setting time, color,.. value.
- This is pretty straightforward, assuming you already have the World, View, and Projection matrix.
- In the shader, the matrix is column-major, not row-major, this is because the GPU is faster at calculating column-major matrix, so we need to transpose the matrix first. I will not go into detail about how the matrix works here.
D3DXMATRIX World, View, Projection; // get the current world, view and projection matrix d3ddev->GetTransform(D3DTS_WORLD, &World); d3ddev->GetTransform(D3DTS_VIEW, &View); d3ddev->GetTransform(D3DTS_PROJECTION, &Projection); D3DXMATRIX WorldViewProjection, WorldViewProjectionTransposed; WorldViewProjection = World * View * Projection; D3DXMatrixTranspose(&WorldViewProjectionTransposed, &WorldViewProjection);
- As we already specified that the
WorldViewProj
constant buffer in the Vertex Shader is at theregister(c0)
in the previous chapter:cbuffer cbPerFrame : register(c0) { matrix WorldViewProj : register(c0); };
- We'll need to set the
StartRegister
parameter of theSetVertexShaderConstantF
method to0
. TheVector4fCount
is set to4
, which indicates that this is a 4x4 float buffer. (Vector4fCount x 4)d3ddev->SetVertexShaderConstantF(0, WorldViewProjectionTransposed, 4);
- The format of the color is (R, G, B, A), ranges from 0.f to 1.f, let's make a green color:
float psConstant[] = {0.f, 1.f, 0.f, 1.f};
- As we already specified that the
color
constant buffer in the Pixel Shader is at theregister(c0)
in the previous chapter:cbuffer cbPerFrame : register(c0) { float4 color : register(c0); };
- We'll need to set the
StartRegister
parameter of theSetPixelShaderConstantF
method to0
. TheVector4fCount
is set to1
, indicates that this is a 1x4 float buffer. (Vector4fCount x 4)d3ddev->SetPixelShaderConstantF(0, psConstant, 1);
- Think about it as an index in the buffer, each register will hold 128 bits of data, which is four float/int values.
- For example, you can have two colors for the pixel shader by:
cbuffer cbPerFrame : register(c0) { float4 color_a : register(c0); float4 color_b : register(c1); };
- And in C++:
float psConstant[] = { 0.f, 1.f, 0.f, 1.f, // color_a in the shader 1.f, 0.f, 0.f, 1.f, // color_b in the shader }; d3ddev->SetPixelShaderConstantF(0, psConstant, 2); // 2 x 4 float buffer
- As you might have noticed, the buffer goes by 4 values at a time, and you might need to only pass a single value, in which case, you can do it like this:
cbuffer cbPerFrame : register(c0) { float time : register(c0); float angle : register(c1); };
float time = 10.f; float angle = D3DX_PI; float psConstant[] = { time, 0.f, 0.f, 0.f, // reserve 3 values angle, 0.f, 0.f, 0.f, // reserve 3 values }; d3ddev->SetPixelShaderConstantF(0, psConstant, 2);
- But that is a waste of space and performance, do this instead:
cbuffer cbPerFrame : register(c0) { float timeAndAngle : register(c0); }; // access it later by // float time = timeAndAngle[0]; // float angle = timeAndAngle[1];
float time = 10.f; float angle = D3DX_PI; float psConstant[] = { time, angle, 0.f, 0.f, // reserve 2 values }; d3ddev->SetPixelShaderConstantF(0, psConstant, 1);