Instancing & Skinning
Input layout entries for slot 1 use D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA with InstanceDataStepRate = 1.
24.1 Instancing with per-instance vertex data
Input layout entries for slot 1 use D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA with InstanceDataStepRate = 1. Draw with DrawIndexedInstanced(indexCount, instanceCount, ...).
struct InstancedIn
{
float3 pos : POSITION; // slot 0, per vertex
float3 normal : NORMAL;
float4x4 world : INSTANCE_WORLD; // slot 1, per instance (occupies INSTANCE_WORLD0..3)
float4 color : INSTANCE_COLOR;
};24.2 Instancing from a structured buffer (preferred today)
Combine with ExecuteIndirect and GPU culling for GPU-driven rendering. Remember SV_InstanceID does not include StartInstanceLocation — add it yourself (root constant, or SV_StartInstanceLocation in SM 6.8).
struct InstanceData { float4x4 world; float4 color; };
StructuredBuffer<InstanceData> gInstances : register(t0, space1);
struct InstOut { float4 pos : SV_Position; float3 n : NORMAL; float4 color : COLOR; };
InstOut InstancedVS(float3 pos : POSITION, float3 n : NORMAL, uint iid : SV_InstanceID)
{
InstanceData inst = gInstances[iid];
InstOut o;
float4 posW = mul(inst.world, float4(pos, 1));
o.pos = mul(gViewProj, posW);
o.n = normalize(mul((float3x3)inst.world, n));
o.color = inst.color;
return o;
}24.3 Skeletal animation (linear blend skinning)
Dual quaternion skinning avoids the "candy wrapper" volume loss of linear blending. Many engines skin in a compute shader once per frame and reuse the result for all passes (depth, shadows, main, motion vectors).
StructuredBuffer<float4x4> gBoneMatrices : register(t1, space1); // bone → world (bind pose inverse included)
struct SkinnedIn
{
float3 pos : POSITION;
float3 normal : NORMAL;
uint4 bones : BLENDINDICES; // DXGI_FORMAT_R8G8B8A8_UINT
float4 weights : BLENDWEIGHT; // DXGI_FORMAT_R8G8B8A8_UNORM, sum = 1
};
InstOut SkinnedVS(SkinnedIn i)
{
float4x4 skin = gBoneMatrices[i.bones.x] * i.weights.x
+ gBoneMatrices[i.bones.y] * i.weights.y
+ gBoneMatrices[i.bones.z] * i.weights.z
+ gBoneMatrices[i.bones.w] * i.weights.w; // component-wise scale & sum is correct here
float4 posW = mul(skin, float4(i.pos, 1));
InstOut o;
o.pos = mul(gViewProj, posW);
o.n = normalize(mul((float3x3)skin, i.normal));
o.color = 1;
return o;
}24.4 Morph targets (blend shapes)
StructuredBuffer<float3> gMorphDeltas : register(t2, space1); // [target][vertex]
cbuffer Morph : register(b2, space1) { float4 gMorphWeights[2]; uint gVertexCount; }; // up to 8 targets
float3 ApplyMorphs(float3 pos, uint vid)
{
[unroll] for (uint t = 0; t < 8; ++t)
pos += gMorphDeltas[t * gVertexCount + vid] * gMorphWeights[t / 4][t % 4];
return pos;
}🧪 Part II Exercises
Write a cbuffer with float3, float, float2, float3, float[4], float4x4 members; compute every offset by hand, then verify with the -Fc disassembly and a static_assert on the matching C++ struct.
Convert a project from cbuffer syntax to ConstantBuffer<T> with explicit register(bN, spaceM) for per-frame, per-material, and per-draw data.
Author a root signature in HLSL with root constants, a root CBV, a descriptor table, and two static samplers; compile it with -T rootsig_1_1 and create the PSO from it.
Render a rotating, lit cube: world/view/projection matrices, inverse-transpose normals, and a camera you can orbit — verify you can switch between mul(v, M) and mul(M, v) conventions correctly.
Implement Blinn–Phong with directional, point, and spot lights stored in a StructuredBuffer<Light>; add a toon-shading toggle.
Add normal mapping with a TBN matrix; then implement the derivative-based version and compare quality.
Add a skybox and an environment-reflection shader whose blurriness depends on roughness via SampleLevel.
Build a post-processing chain: HDR target → bloom (downsample/upsample) → ACES tone mapping → vignette → sRGB back buffer.
Implement shadow mapping with PCF via SampleCmpLevelZero; then extend it to four cascades in a Texture2DArray.
Render 10,000 instances from a StructuredBuffer with per-instance colors; then skin an animated character with a bone-matrix buffer.