collada_scene: render skinned animation

This commit is contained in:
Zack Buhman 2026-01-30 14:45:11 -06:00
parent b72f978f6a
commit d7183c1b39
8 changed files with 151 additions and 52 deletions

View File

@ -21,6 +21,7 @@ CFLAGS += -march=core2
CFLAGS += -Wall -Werror -Wfatal-errors CFLAGS += -Wall -Werror -Wfatal-errors
CFLAGS += -Wno-unused-but-set-variable CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wno-unknown-pragmas CFLAGS += -Wno-unknown-pragmas
CFLAGS += -Wno-error=unused-variable
CFLAGS += -I./include CFLAGS += -I./include
CFLAGS += -municode CFLAGS += -municode
LDFLAGS += -municode LDFLAGS += -municode

View File

@ -144,7 +144,8 @@ def skin_vertex_buffer(collada, skin, vertex_index_table):
def emit(column, cls): def emit(column, cls):
for i in range(4): for i in range(4):
if i >= len(influences): if i >= len(influences):
vertex_buffer.append(cls(0)) value = cls(0)
vertex_buffer.append(value)
else: else:
value = cls(influences[i][column]) value = cls(influences[i][column])
assert type(influences[i][column])(value) == influences[i][column] assert type(influences[i][column])(value) == influences[i][column]

View File

@ -6,8 +6,8 @@
<authoring_tool>OpenCOLLADA for 3ds Max; Version: 1.6; Revision: 68</authoring_tool> <authoring_tool>OpenCOLLADA for 3ds Max; Version: 1.6; Revision: 68</authoring_tool>
<source_data>file:///C:/cygwin/home/bilbo/d3d10/scenes/curve_interpolation/curve_interpolation.max</source_data> <source_data>file:///C:/cygwin/home/bilbo/d3d10/scenes/curve_interpolation/curve_interpolation.max</source_data>
</contributor> </contributor>
<created>2026-01-30T09:40:47</created> <created>2026-01-30T14:43:57</created>
<modified>2026-01-30T09:40:47</modified> <modified>2026-01-30T14:43:57</modified>
<unit name="inch" meter="0.0254"/> <unit name="inch" meter="0.0254"/>
<up_axis>Z_UP</up_axis> <up_axis>Z_UP</up_axis>
</asset> </asset>
@ -1513,12 +1513,12 @@
<instance_geometry url="#geom-Cube"> <instance_geometry url="#geom-Cube">
<bind_material> <bind_material>
<technique_common> <technique_common>
<instance_material symbol="Material__15_1" target="#Material__15-material"/>
<instance_material symbol="Material__17_1" target="#Material__17-material"/> <instance_material symbol="Material__17_1" target="#Material__17-material"/>
<instance_material symbol="Material__16_1" target="#Material__16-material"/>
<instance_material symbol="Material__18_1" target="#Material__18-material"/> <instance_material symbol="Material__18_1" target="#Material__18-material"/>
<instance_material symbol="Material__19_1" target="#Material__19-material"/> <instance_material symbol="Material__19_1" target="#Material__19-material"/>
<instance_material symbol="Material__20_1" target="#Material__20-material"/> <instance_material symbol="Material__20_1" target="#Material__20-material"/>
<instance_material symbol="Material__15_1" target="#Material__15-material"/>
<instance_material symbol="Material__16_1" target="#Material__16-material"/>
</technique_common> </technique_common>
</bind_material> </bind_material>
</instance_geometry> </instance_geometry>
@ -1655,8 +1655,8 @@
<bind_material> <bind_material>
<technique_common> <technique_common>
<instance_material symbol="Material__13_1" target="#Material__13-material"/> <instance_material symbol="Material__13_1" target="#Material__13-material"/>
<instance_material symbol="Material__14_1" target="#Material__14-material"/>
<instance_material symbol="Material__15" target="#Material__15_1-material"/> <instance_material symbol="Material__15" target="#Material__15_1-material"/>
<instance_material symbol="Material__14_1" target="#Material__14-material"/>
<instance_material symbol="Material__16" target="#Material__16_1-material"/> <instance_material symbol="Material__16" target="#Material__16_1-material"/>
<instance_material symbol="Material__17" target="#Material__17_1-material"/> <instance_material symbol="Material__17" target="#Material__17_1-material"/>
<instance_material symbol="Material__18" target="#Material__18_1-material"/> <instance_material symbol="Material__18" target="#Material__18_1-material"/>

View File

@ -314,7 +314,7 @@ namespace collada {
XMVECTOR axis = XMVectorSet(0, 1, 0, 0); XMVECTOR axis = XMVectorSet(0, 1, 0, 0);
XMVECTOR axisZ = XMVectorSet(0, 0, 1, 0); XMVECTOR axisZ = XMVectorSet(0, 0, 1, 0);
XMMATRIX joint0 = XMMatrixScaling(1, 1, 1); XMMATRIX joint0 = XMMatrixScaling(1, 1, 1);
joint0 = XMMatrixTranslation(10, 0, 0) * joint0; //joint0 = XMMatrixTranslation(10, 0, 0) * joint0;
joint0 = XMMatrixRotationNormal(axis, XMConvertToRadians(-90)) * joint0; joint0 = XMMatrixRotationNormal(axis, XMConvertToRadians(-90)) * joint0;
XMMATRIX joint1 = XMMatrixScaling(1, 1, 1); XMMATRIX joint1 = XMMatrixScaling(1, 1, 1);
@ -332,9 +332,26 @@ namespace collada {
= XMMatrixRotationNormal(axisZ, sin(t)) * XMMatrixTranslation(10, 0, 0) * joint0 = XMMatrixRotationNormal(axisZ, sin(t)) * XMMatrixTranslation(10, 0, 0) * joint0
; ;
*/ */
XMMATRIX joint0ibm = XMLoadFloat4x4((XMFLOAT4X4*)&inverse_bind_matrices[0 * 16]); XMMATRIX joint0ibm = XMLoadFloat4x4((XMFLOAT4X4*)&inverse_bind_matrices[0 * 16]);
XMMATRIX joint1ibm = XMLoadFloat4x4((XMFLOAT4X4*)&inverse_bind_matrices[1 * 16]); XMMATRIX joint1ibm = XMLoadFloat4x4((XMFLOAT4X4*)&inverse_bind_matrices[1 * 16]);
XMFLOAT4X4 foo;
XMStoreFloat4x4(&foo, joint0);
print(" %.1f %.1f %.1f %.1f\n", foo._11, foo._12, foo._13, foo._14);
print(" %.1f %.1f %.1f %.1f\n", foo._21, foo._22, foo._23, foo._24);
print(" %.1f %.1f %.1f %.1f\n", foo._31, foo._32, foo._33, foo._34);
print(" %.1f %.1f %.1f %.1f\n", foo._41, foo._42, foo._43, foo._44);
print("\n");
XMStoreFloat4x4(&foo, joint1);
print("joint1ibm:\n");
print(" %.1f %.1f %.1f %.1f\n", foo._11, foo._12, foo._13, foo._14);
print(" %.1f %.1f %.1f %.1f\n", foo._21, foo._22, foo._23, foo._24);
print(" %.1f %.1f %.1f %.1f\n", foo._31, foo._32, foo._33, foo._34);
print(" %.1f %.1f %.1f %.1f\n", foo._41, foo._42, foo._43, foo._44);
print("\n");
exit(0);
XMMATRIX mJoints[2] = { XMMATRIX mJoints[2] = {
joint0ibm * joint0, joint0ibm * joint0,
joint1ibm * joint1, joint1ibm * joint1,

View File

@ -19,11 +19,14 @@ namespace collada_scene {
ID3D10Effect * g_pEffect = NULL; ID3D10Effect * g_pEffect = NULL;
ID3D10EffectTechnique * g_pTechniqueBlinn = NULL; ID3D10EffectTechnique * g_pTechniqueBlinn = NULL;
ID3D10EffectTechnique * g_pTechniqueBlinnSkin = NULL;
ID3D10EffectMatrixVariable * g_pWorldVariable = NULL; ID3D10EffectMatrixVariable * g_pWorldVariable = NULL;
ID3D10EffectMatrixVariable * g_pViewVariable = NULL; ID3D10EffectMatrixVariable * g_pViewVariable = NULL;
ID3D10EffectMatrixVariable * g_pProjectionVariable = NULL; ID3D10EffectMatrixVariable * g_pProjectionVariable = NULL;
ID3D10EffectMatrixVariable * g_pJointsVariable = NULL;
ID3D10EffectVectorVariable * g_pViewEyeVariable = NULL; ID3D10EffectVectorVariable * g_pViewEyeVariable = NULL;
ID3D10EffectVectorVariable * g_pLightPosVariable = NULL; ID3D10EffectVectorVariable * g_pLightPosVariable = NULL;
ID3D10EffectVectorVariable * g_pLightDirVariable = NULL; ID3D10EffectVectorVariable * g_pLightDirVariable = NULL;
@ -253,7 +256,7 @@ namespace collada_scene {
{ {
HRESULT hr; HRESULT hr;
D3D10_INPUT_ELEMENT_DESC layout[inputs.elements_count + 2]; D3D10_INPUT_ELEMENT_DESC layout[inputs.elements_count + skin_inputs.elements_count];
UINT byte_offset = 0; UINT byte_offset = 0;
for (int i = 0; i < inputs.elements_count; i++) { for (int i = 0; i < inputs.elements_count; i++) {
@ -291,7 +294,7 @@ namespace collada_scene {
layout[ix].SemanticName = skin_inputs.elements[i].semantic; layout[ix].SemanticName = skin_inputs.elements[i].semantic;
layout[ix].SemanticIndex = skin_inputs.elements[i].semantic_index; layout[ix].SemanticIndex = skin_inputs.elements[i].semantic_index;
layout[ix].Format = dxgi_format(skin_inputs.elements[i].format); layout[ix].Format = dxgi_format(skin_inputs.elements[i].format);
layout[ix].InputSlot = 0; layout[ix].InputSlot = 1;
layout[ix].AlignedByteOffset = skin_byte_offset; layout[ix].AlignedByteOffset = skin_byte_offset;
layout[ix].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; layout[ix].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
layout[ix].InstanceDataStepRate = 0; layout[ix].InstanceDataStepRate = 0;
@ -299,6 +302,8 @@ namespace collada_scene {
skin_byte_offset += format_size(skin_inputs.elements[i].format); skin_byte_offset += format_size(skin_inputs.elements[i].format);
} }
g_pTechniqueBlinnSkin->GetPassByIndex(0)->GetDesc(&passDesc);
hr = g_pd3dDevice->CreateInputLayout(layout, inputs.elements_count + skin_inputs.elements_count, hr = g_pd3dDevice->CreateInputLayout(layout, inputs.elements_count + skin_inputs.elements_count,
passDesc.pIAInputSignature, passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize, passDesc.IAInputSignatureSize,
@ -335,11 +340,14 @@ namespace collada_scene {
} }
g_pTechniqueBlinn = g_pEffect->GetTechniqueByName("Blinn"); g_pTechniqueBlinn = g_pEffect->GetTechniqueByName("Blinn");
g_pTechniqueBlinnSkin = g_pEffect->GetTechniqueByName("BlinnSkin");
g_pWorldVariable = g_pEffect->GetVariableByName("World")->AsMatrix(); g_pWorldVariable = g_pEffect->GetVariableByName("World")->AsMatrix();
g_pViewVariable = g_pEffect->GetVariableByName("View")->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName("View")->AsMatrix();
g_pProjectionVariable = g_pEffect->GetVariableByName("Projection")->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName("Projection")->AsMatrix();
g_pJointsVariable = g_pEffect->GetVariableByName("Joints")->AsMatrix();
g_pViewEyeVariable = g_pEffect->GetVariableByName("ViewEye")->AsVector(); g_pViewEyeVariable = g_pEffect->GetVariableByName("ViewEye")->AsVector();
g_pLightPosVariable = g_pEffect->GetVariableByName("LightPos")->AsVector(); g_pLightPosVariable = g_pEffect->GetVariableByName("LightPos")->AsVector();
g_pLightDirVariable = g_pEffect->GetVariableByName("LightDir")->AsVector(); g_pLightDirVariable = g_pEffect->GetVariableByName("LightDir")->AsVector();
@ -497,9 +505,6 @@ namespace collada_scene {
mesh const& mesh = geometry.mesh; mesh const& mesh = geometry.mesh;
g_pd3dDevice->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, mesh.index_buffer_offset); g_pd3dDevice->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, mesh.index_buffer_offset);
D3D10_TECHNIQUE_DESC techDesc;
g_pTechniqueBlinn->GetDesc(&techDesc);
for (int j = 0; j < instance_materials_count; j++) { for (int j = 0; j < instance_materials_count; j++) {
instance_material const& instance_material = instance_materials[j]; instance_material const& instance_material = instance_materials[j];
triangles const& triangles = mesh.triangles[instance_material.element_index]; triangles const& triangles = mesh.triangles[instance_material.element_index];
@ -524,9 +529,6 @@ namespace collada_scene {
mesh const& mesh = skin.geometry->mesh; mesh const& mesh = skin.geometry->mesh;
g_pd3dDevice->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, mesh.index_buffer_offset); g_pd3dDevice->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, mesh.index_buffer_offset);
D3D10_TECHNIQUE_DESC techDesc;
g_pTechniqueBlinn->GetDesc(&techDesc);
for (int j = 0; j < instance_materials_count; j++) { for (int j = 0; j < instance_materials_count; j++) {
instance_material const& instance_material = instance_materials[j]; instance_material const& instance_material = instance_materials[j];
triangles const& triangles = mesh.triangles[instance_material.element_index]; triangles const& triangles = mesh.triangles[instance_material.element_index];
@ -539,7 +541,7 @@ namespace collada_scene {
g_pd3dDevice->IASetVertexBuffers(0, numBuffers, m_pVertexBuffers, strides, offsets); g_pd3dDevice->IASetVertexBuffers(0, numBuffers, m_pVertexBuffers, strides, offsets);
g_pd3dDevice->IASetInputLayout(m_pSkinnedVertexLayouts[triangles.inputs_index]); g_pd3dDevice->IASetInputLayout(m_pSkinnedVertexLayouts[triangles.inputs_index]);
g_pTechniqueBlinn->GetPassByIndex(0)->Apply(0); g_pTechniqueBlinnSkin->GetPassByIndex(0)->Apply(0);
g_pd3dDevice->DrawIndexed(triangles.count * 3, triangles.index_offset, 0); g_pd3dDevice->DrawIndexed(triangles.count * 3, triangles.index_offset, 0);
} }
} }
@ -560,6 +562,34 @@ namespace collada_scene {
{ {
for (int i = 0; i < instance_controllers_count; i++) { for (int i = 0; i < instance_controllers_count; i++) {
instance_controller const &instance_controller = instance_controllers[i]; instance_controller const &instance_controller = instance_controllers[i];
skin const &skin = instance_controller.controller->skin;
#if 0
float Joints[] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 0.0,
0.0, 0.7, -0.7, 0.0,
-0.0, 0.7, 0.7, 0.0,
-0.0, -7.5, 3.3, 1.0,
};
#else
XMFLOAT4X4 Joints[instance_controller.joint_count];
for (int joint_index = 0; joint_index < instance_controller.joint_count; joint_index++) {
XMMATRIX ibm = XMLoadFloat4x4((XMFLOAT4X4*)&skin.inverse_bind_matrices[joint_index]);
int node_index = instance_controller.joint_node_indices[joint_index];
node_instance& node_instance = m_nodeInstances[node_index];
XMStoreFloat4x4(&Joints[joint_index], ibm * node_instance.world);
}
#endif
g_pJointsVariable->SetMatrixArray((float *)Joints, 0, instance_controller.joint_count);
render_skin(instance_controller.controller->skin, render_skin(instance_controller.controller->skin,
instance_controller.instance_materials, instance_controller.instance_materials,
instance_controller.instance_materials_count); instance_controller.instance_materials_count);

View File

@ -15,6 +15,11 @@ cbuffer cbMultiplePerFrame
matrix World; matrix World;
}; };
cbuffer cbMultiplePerController
{
matrix Joints[16];
};
cbuffer cbPerMaterial cbuffer cbPerMaterial
{ {
float4 Emission; float4 Emission;
@ -37,6 +42,15 @@ SamplerState samLinear {
AddressV = Wrap; AddressV = Wrap;
}; };
struct VS_INPUT_SKINNED
{
float3 Pos : POSITION;
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;
int4 Joint : BLENDINDICES0;
float4 Weight: BLENDWEIGHT0;
};
struct VS_INPUT struct VS_INPUT
{ {
float3 Pos : POSITION; float3 Pos : POSITION;
@ -52,6 +66,30 @@ struct PS_INPUT
float4 WPos : POSITION; float4 WPos : POSITION;
}; };
PS_INPUT VSSkin(VS_INPUT_SKINNED input)
{
PS_INPUT output;
matrix mSkin
= input.Weight.x * Joints[input.Joint.x]
+ input.Weight.y * Joints[input.Joint.y]
+ input.Weight.z * Joints[input.Joint.z]
+ input.Weight.w * Joints[input.Joint.w]
;
float4 world_pos = mul(float4(input.Pos, 1), mSkin);
//float4 world_pos = mul(float4(input.Pos, 1), World);
output.Pos = mul(world_pos, View);
output.Pos = mul(output.Pos, Projection);
output.Norm = mul(input.Norm, (float3x3)World);
output.Tex = input.Tex;
output.WPos = world_pos;
return output;
}
PS_INPUT VS(VS_INPUT input) PS_INPUT VS(VS_INPUT input)
{ {
PS_INPUT output; PS_INPUT output;
@ -84,7 +122,7 @@ float4 PS(PS_INPUT input) : SV_Target
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
float3 light_dir = normalize(-LightDir[i].xyz); float3 light_dir = normalize(-LightDir[i].xyz);
float diffuse_intensity = max(dot(normal, light_dir), 0.0); float diffuse_intensity = max(dot(normal, light_dir), 0.0) + 0.2;
float distance = length(LightPos[i].xyz - input.WPos.xyz); float distance = length(LightPos[i].xyz - input.WPos.xyz);
float attenuation = 1.0 / (0.002 * distance * distance); float attenuation = 1.0 / (0.002 * distance * distance);
@ -117,3 +155,15 @@ technique10 Blinn
SetDepthStencilState(EnableDepth, 0); SetDepthStencilState(EnableDepth, 0);
} }
} }
technique10 BlinnSkin
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, VSSkin()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS()));
SetBlendState(DisableBlending, float4(0.0, 0.0, 0.0, 0.0), 0xffffffff);
SetDepthStencilState(EnableDepth, 0);
}
}

View File

@ -543,15 +543,15 @@ float const array_node_bone002_rotationz_angle_input_array[] = {
}; };
float const array_node_bone002_rotationz_angle_output_array[] = { float const array_node_bone002_rotationz_angle_output_array[] = {
180.0f, 180.0f + 180.0f,
230.0f, 230.0f + 180.0f,
180.0f, 180.0f + 180.0f,
130.0f, 130.0f + 180.0f,
180.0f, 180.0f + 180.0f,
230.0f, 230.0f + 180.0f,
180.0f, 180.0f + 180.0f,
130.0f, 130.0f + 180.0f,
180.0f, 180.0f + 180.0f,
}; };
float const array_node_bone002_rotationz_angle_intangent_array[] = { float const array_node_bone002_rotationz_angle_intangent_array[] = {
@ -1652,8 +1652,17 @@ transform const transforms_node_cube[] = {
instance_material const instance_geometry_instance_materials_node_cube_0[] = { instance_material const instance_geometry_instance_materials_node_cube_0[] = {
{ {
.element_index = 5, // an index into mesh.triangles .element_index = 1, // an index into mesh.triangles
.material = &material_material__17_material, .material = &material_material__15_material,
.emission = { .input_set = -1 },
.ambient = { .input_set = -1 },
.diffuse = { .input_set = -1 },
.specular = { .input_set = -1 },
},
{
.element_index = 0, // an index into mesh.triangles
.material = &material_material__16_material,
.emission = { .input_set = -1 }, .emission = { .input_set = -1 },
.ambient = { .input_set = -1 }, .ambient = { .input_set = -1 },
@ -1669,6 +1678,15 @@ instance_material const instance_geometry_instance_materials_node_cube_0[] = {
.diffuse = { .input_set = -1 }, .diffuse = { .input_set = -1 },
.specular = { .input_set = -1 }, .specular = { .input_set = -1 },
}, },
{
.element_index = 5, // an index into mesh.triangles
.material = &material_material__17_material,
.emission = { .input_set = -1 },
.ambient = { .input_set = -1 },
.diffuse = { .input_set = -1 },
.specular = { .input_set = -1 },
},
{ {
.element_index = 2, // an index into mesh.triangles .element_index = 2, // an index into mesh.triangles
.material = &material_material__19_material, .material = &material_material__19_material,
@ -1682,24 +1700,6 @@ instance_material const instance_geometry_instance_materials_node_cube_0[] = {
.element_index = 4, // an index into mesh.triangles .element_index = 4, // an index into mesh.triangles
.material = &material_material__20_material, .material = &material_material__20_material,
.emission = { .input_set = -1 },
.ambient = { .input_set = -1 },
.diffuse = { .input_set = -1 },
.specular = { .input_set = -1 },
},
{
.element_index = 1, // an index into mesh.triangles
.material = &material_material__15_material,
.emission = { .input_set = -1 },
.ambient = { .input_set = -1 },
.diffuse = { .input_set = -1 },
.specular = { .input_set = -1 },
},
{
.element_index = 0, // an index into mesh.triangles
.material = &material_material__16_material,
.emission = { .input_set = -1 }, .emission = { .input_set = -1 },
.ambient = { .input_set = -1 }, .ambient = { .input_set = -1 },
.diffuse = { .input_set = -1 }, .diffuse = { .input_set = -1 },
@ -1994,8 +1994,8 @@ instance_light const instance_lights_node_geosphere[] = {
}; };
channel const * const node_channels_node_geosphere[] = { channel const * const node_channels_node_geosphere[] = {
&node_channel_node_geosphere_scale,
&node_channel_node_geosphere_inversescaleaxisrotation, &node_channel_node_geosphere_inversescaleaxisrotation,
&node_channel_node_geosphere_scale,
&node_channel_node_geosphere_scaleaxisrotation, &node_channel_node_geosphere_scaleaxisrotation,
}; };
@ -2140,8 +2140,8 @@ int const joint_node_indices_node_box001_geom_box001_skin1[] = {
instance_material const instance_controller_instance_materials_node_box001_0[] = { instance_material const instance_controller_instance_materials_node_box001_0[] = {
{ {
.element_index = 1, // an index into mesh.triangles .element_index = 0, // an index into mesh.triangles
.material = &material_material__13_material, .material = &material_material__14_material,
.emission = { .input_set = -1 }, .emission = { .input_set = -1 },
.ambient = { .input_set = -1 }, .ambient = { .input_set = -1 },
@ -2149,8 +2149,8 @@ instance_material const instance_controller_instance_materials_node_box001_0[] =
.specular = { .input_set = -1 }, .specular = { .input_set = -1 },
}, },
{ {
.element_index = 0, // an index into mesh.triangles .element_index = 1, // an index into mesh.triangles
.material = &material_material__14_material, .material = &material_material__13_material,
.emission = { .input_set = -1 }, .emission = { .input_set = -1 },
.ambient = { .input_set = -1 }, .ambient = { .input_set = -1 },