Wicked Engine

Abuse the immediate constant buffer!

· Devblog

Very often, I need to draw simple geometries, like cubes, and I want to do the minimal amount of graphics state setup. With this technique, you don’t have to set up a vertex buffer or input layout, which means, we don’t have to write the boilerplate resource creation code for them, and don’t have to call the binding code, which also lightens the API overhead.

An immediate constant buffer differs from a regular constant buffer in a few aspects:

So when I declare a vertex array inside a shader, for example, like this:

static const float4 CUBE[]={

float4(-1.0,1.0,1.0,1.0),

float4(-1.0,-1.0,1.0,1.0),

float4(-1.0,-1.0,-1.0,1.0),

float4(1.0,1.0,1.0,1.0),

float4(1.0,-1.0,1.0,1.0),

float4(-1.0,-1.0,1.0,1.0),

float4(1.0,1.0,-1.0,1.0),

float4(1.0,-1.0,-1.0,1.0),

float4(1.0,-1.0,1.0,1.0),

float4(-1.0,1.0,-1.0,1.0),

float4(-1.0,-1.0,-1.0,1.0),

float4(1.0,-1.0,-1.0,1.0),

float4(-1.0,-1.0,1.0,1.0),

float4(1.0,-1.0,1.0,1.0),

float4(1.0,-1.0,-1.0,1.0),

float4(1.0,1.0,1.0,1.0),

float4(-1.0,1.0,1.0,1.0),

float4(-1.0,1.0,-1.0,1.0),

float4(-1.0,1.0,-1.0,1.0),

float4(-1.0,1.0,1.0,1.0),

float4(-1.0,-1.0,-1.0,1.0),

float4(-1.0,1.0,1.0,1.0),

float4(1.0,1.0,1.0,1.0),

float4(-1.0,-1.0,1.0,1.0),

float4(1.0,1.0,1.0,1.0),

float4(1.0,1.0,-1.0,1.0),

float4(1.0,-1.0,1.0,1.0),

float4(1.0,1.0,-1.0,1.0),

float4(-1.0,1.0,-1.0,1.0),

float4(1.0,-1.0,-1.0,1.0),

float4(-1.0,-1.0,-1.0,1.0),

float4(-1.0,-1.0,1.0,1.0),

float4(1.0,-1.0,-1.0,1.0),

float4(1.0,1.0,-1.0,1.0),

float4(1.0,1.0,1.0,1.0),

float4(-1.0,1.0,-1.0,1.0),

};
...and if I want to draw this cube, then the simplest vertex shader should look like this:
float4 main(uint vID : SV_VERTEXID) : SV_Position

{

return mul(CUBE[vID], g_xTransform);

}
(where g_xTransform is the World*View*Projection matrix from a regular constant buffer)
I would then call the Draw from the DX11 API with a vertexcount of 36 because that is the array length of the CUBE vertex array. The shader automatically gets the SV_VERTEXID semantic from the input assembler, which directly indexes into the vertex array. I find this technique very clean both from the C++ side and the shader side, so I use it very frequently.
A few example use-cases:

Deferred light geometries
Light volume geometries
Occlusion culling occludees
Decals
Skybox/skysphere
Light probe debug geometries

If you need vertex arrays like this for some other simple meshes:

Cone
Icosphere
UV Sphere
Circle
Cube
Quad

That's it, cheers!