collada: draw animated joints

This commit is contained in:
Zack Buhman 2026-03-17 16:11:55 -05:00
parent 71744c4344
commit f4e95aee09
7 changed files with 107 additions and 29 deletions

View File

@ -1,7 +1,7 @@
set -eux
PYTHONPATH=~/d3d10 python -m collada.main \
path/to/noodle.DAE \
~/love-demo/scene/noodle/noodle.DAE \
data/scenes/noodle/noodle.cpp \
data/scenes/noodle/noodle.vtx \
data/scenes/noodle/noodle.vjw \

View File

@ -1913,6 +1913,8 @@ channel const * const node_channels_node_environmentambientlight[] = {
};
node const node_node_environmentambientlight = {
.name = "EnvironmentAmbientLight",
.parent_index = -1,
.type = node_type::NODE,
@ -1953,6 +1955,8 @@ channel const * const node_channels_node_cameratargethelper[] = {
};
node const node_node_cameratargethelper = {
.name = "CameraTargetHelper",
.parent_index = -1,
.type = node_type::NODE,
@ -1993,6 +1997,8 @@ channel const * const node_channels_node_camera_target[] = {
};
node const node_node_camera_target = {
.name = "Camera.Target",
.parent_index = 1,
.type = node_type::NODE,
@ -2040,6 +2046,8 @@ channel const * const node_channels_node_omni001[] = {
};
node const node_node_omni001 = {
.name = "Omni001",
.parent_index = -1,
.type = node_type::NODE,
@ -2103,6 +2111,8 @@ channel const * const node_channels_node_box001[] = {
};
node const node_node_box001 = {
.name = "Box001",
.parent_index = -1,
.type = node_type::NODE,
@ -2143,6 +2153,8 @@ channel const * const node_channels_node_bonehelper[] = {
};
node const node_node_bonehelper = {
.name = "BoneHelper",
.parent_index = -1,
.type = node_type::NODE,
@ -2204,18 +2216,20 @@ instance_light const instance_lights_node_bone001[] = {
};
channel const * const node_channels_node_bone001[] = {
&node_channel_node_bone001_translation_x,
&node_channel_node_bone001_translation_z,
&node_channel_node_bone001_scale,
&node_channel_node_bone001_translation_y,
&node_channel_node_bone001_rotationz_angle,
&node_channel_node_bone001_scaleaxisrotation,
&node_channel_node_bone001_rotationx_angle,
&node_channel_node_bone001_rotationy_angle,
&node_channel_node_bone001_rotationz_angle,
&node_channel_node_bone001_translation_y,
&node_channel_node_bone001_translation_z,
&node_channel_node_bone001_rotationx_angle,
&node_channel_node_bone001_inversescaleaxisrotation,
&node_channel_node_bone001_scale,
&node_channel_node_bone001_scaleaxisrotation,
&node_channel_node_bone001_translation_x,
};
node const node_node_bone001 = {
.name = "Bone001",
.parent_index = 5,
.type = node_type::JOINT,
@ -2277,18 +2291,20 @@ instance_light const instance_lights_node_bone002[] = {
};
channel const * const node_channels_node_bone002[] = {
&node_channel_node_bone002_translation_x,
&node_channel_node_bone002_inversescaleaxisrotation,
&node_channel_node_bone002_translation_y,
&node_channel_node_bone002_scale,
&node_channel_node_bone002_rotationx_angle,
&node_channel_node_bone002_rotationy_angle,
&node_channel_node_bone002_inversescaleaxisrotation,
&node_channel_node_bone002_scaleaxisrotation,
&node_channel_node_bone002_translation_x,
&node_channel_node_bone002_rotationy_angle,
&node_channel_node_bone002_rotationz_angle,
&node_channel_node_bone002_rotationx_angle,
&node_channel_node_bone002_translation_z,
};
node const node_node_bone002 = {
.name = "Bone002",
.parent_index = 6,
.type = node_type::JOINT,
@ -2350,18 +2366,20 @@ instance_light const instance_lights_node_bone003[] = {
};
channel const * const node_channels_node_bone003[] = {
&node_channel_node_bone003_translation_y,
&node_channel_node_bone003_rotationy_angle,
&node_channel_node_bone003_translation_x,
&node_channel_node_bone003_rotationz_angle,
&node_channel_node_bone003_inversescaleaxisrotation,
&node_channel_node_bone003_rotationx_angle,
&node_channel_node_bone003_translation_z,
&node_channel_node_bone003_scaleaxisrotation,
&node_channel_node_bone003_scale,
&node_channel_node_bone003_rotationz_angle,
&node_channel_node_bone003_rotationy_angle,
&node_channel_node_bone003_rotationx_angle,
&node_channel_node_bone003_scaleaxisrotation,
&node_channel_node_bone003_translation_y,
&node_channel_node_bone003_inversescaleaxisrotation,
&node_channel_node_bone003_translation_z,
&node_channel_node_bone003_translation_x,
};
node const node_node_bone003 = {
.name = "Bone003",
.parent_index = 7,
.type = node_type::JOINT,
@ -2402,6 +2420,8 @@ channel const * const node_channels_node_camerahelper_1[] = {
};
node const node_node_camerahelper_1 = {
.name = "CameraHelper",
.parent_index = -1,
.type = node_type::NODE,
@ -2442,6 +2462,8 @@ channel const * const node_channels_node_camera001[] = {
};
node const node_node_camera001 = {
.name = "Camera001",
.parent_index = 9,
.type = node_type::NODE,
@ -2482,6 +2504,8 @@ channel const * const node_channels_node_cameratargethelper_1[] = {
};
node const node_node_cameratargethelper_1 = {
.name = "CameraTargetHelper",
.parent_index = -1,
.type = node_type::NODE,
@ -2522,6 +2546,8 @@ channel const * const node_channels_node_camera001_target[] = {
};
node const node_node_camera001_target = {
.name = "Camera001.Target",
.parent_index = 11,
.type = node_type::NODE,

View File

@ -17,6 +17,7 @@ namespace collada::scene {
unsigned int vertex_buffer_pnt;
unsigned int vertex_buffer_jw;
unsigned int index_buffer;
unsigned int joint_uniform_buffer;
static_skinned * vertex_arrays;
int * vertex_buffer_strides_pnt;

View File

@ -3,9 +3,16 @@
layout (location = 0) in vec3 Position;
layout (location = 1) in vec3 Normal;
layout (location = 2) in vec2 Texture;
layout (location = 3) in ivec4 BlendIndices;
layout (location = 4) in vec4 BlendWeight;
layout (location = 0) uniform mat4 Transform;
layout (std140, binding = 0) uniform JointsLayout
{
mat4 Joints[64];
};
out vec3 PixelNormal;
out vec2 PixelTexture;
@ -14,5 +21,14 @@ void main()
PixelNormal = Normal;
PixelTexture = vec2(Texture.x, 1.0 - Texture.y);
gl_Position = Transform * vec4(Position, 1);
mat4 skin
= BlendWeight.x * Joints[BlendIndices.x]
+ BlendWeight.y * Joints[BlendIndices.y]
+ BlendWeight.z * Joints[BlendIndices.z]
+ BlendWeight.w * Joints[BlendIndices.w]
;
vec4 position = skin * vec4(Position, 1);
gl_Position = Transform * position;
}

View File

@ -80,7 +80,9 @@ namespace collada::node_state {
case types::transform_type::TRANSLATE:
return XMMatrixTranslationFromVector(transform.vector);
case types::transform_type::ROTATE:
assert(!vector_equal(XMVectorSetW(transform.vector, 0), XMVectorZero()));
//assert(!vector_equal(XMVectorSetW(transform.vector, 0), XMVectorZero()));
if (vector_equal(XMVectorSetW(transform.vector, 0), XMVectorZero()))
return XMMatrixIdentity();
return XMMatrixRotationNormal(transform.vector,
XMConvertToRadians(XMVectorGetW(transform.vector)));
case types::transform_type::SCALE:

View File

@ -50,6 +50,9 @@ namespace collada::scene {
unsigned int diffuse;
unsigned int specular;
} texture_unit;
struct {
unsigned int joint;
} binding;
};
const layout layout = {
@ -84,6 +87,9 @@ namespace collada::scene {
.diffuse = GL_TEXTURE2,
.specular = GL_TEXTURE3,
},
.binding {
.joint = 0,
},
};
unsigned int attribute_location(char const * const semantic,
@ -151,7 +157,11 @@ namespace collada::scene {
glEnableVertexAttribArray(location);
unsigned int gl_size = input_format_gl_size(inputs.elements[i].format);
unsigned int gl_type = input_format_gl_type(inputs.elements[i].format);
glVertexAttribFormat(location, gl_size, gl_type, GL_FALSE, offset);
if (gl_type == GL_INT) {
glVertexAttribIFormat(location, gl_size, gl_type, offset);
} else {
glVertexAttribFormat(location, gl_size, gl_type, GL_FALSE, offset);
}
glVertexAttribBinding(location, binding);
offset += gl_size * 4;
}
@ -179,8 +189,8 @@ namespace collada::scene {
};
const int vertex_buffer_stride_jw
= input_format_gl_size(skin_inputs.elements[0].format)
+ input_format_gl_size(skin_inputs.elements[1].format);
= 4 * input_format_gl_size(skin_inputs.elements[0].format)
+ 4 * input_format_gl_size(skin_inputs.elements[1].format);
void state::load_layouts()
{
@ -209,7 +219,7 @@ namespace collada::scene {
}
}
unsigned int load_vertex_buffer(const char * filename)
static unsigned int load_vertex_buffer(const char * filename)
{
int size;
void * data = read_file(filename, &size);
@ -226,7 +236,7 @@ namespace collada::scene {
return vertex_buffer;
}
unsigned int load_index_buffer(const char * filename)
static unsigned int load_index_buffer(const char * filename)
{
int size;
void * data = read_file(filename, &size);
@ -265,6 +275,13 @@ namespace collada::scene {
glBindTexture(GL_TEXTURE_2D, 0);
}
static unsigned int load_uniform_buffer()
{
unsigned int buffer;
glGenBuffers(1, &buffer);
return buffer;
}
void state::load_scene(types::descriptor const * const descriptor)
{
this->descriptor = descriptor;
@ -274,6 +291,7 @@ namespace collada::scene {
vertex_buffer_pnt = load_vertex_buffer(descriptor->position_normal_texture_buffer);
vertex_buffer_jw = load_vertex_buffer(descriptor->joint_weight_buffer);
index_buffer = load_index_buffer(descriptor->index_buffer);
joint_uniform_buffer = load_uniform_buffer();
load_images();
@ -432,6 +450,21 @@ namespace collada::scene {
types::instance_controller const &instance_controller = instance_controllers[i];
types::skin const &skin = instance_controller.controller->skin;
XMFLOAT4X4 joints[instance_controller.joint_count];
int joints_size = (sizeof (joints));
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];
instance_types::node& node_instance = node_state.node_instances[node_index];
XMStoreFloat4x4(&joints[joint_index], ibm * node_instance.world);
}
glBindBuffer(GL_UNIFORM_BUFFER, joint_uniform_buffer);
glBufferData(GL_UNIFORM_BUFFER, joints_size, (void *)&joints[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, layout.binding.joint, joint_uniform_buffer, 0, joints_size);
draw_skin(skin,
instance_controller.instance_materials,
instance_controller.instance_materials_count);
@ -451,7 +484,7 @@ namespace collada::scene {
}
if (node.instance_controllers_count) {
glUseProgram(collada::effect::program_static);
glUseProgram(collada::effect::program_skinned);
glUniformMatrix4fv(layout.uniform.transform, 1, false, (float *)&float_transform);
draw_instance_controllers(node.instance_controllers, node.instance_controllers_count);
}

View File

@ -309,7 +309,7 @@ void load(const char * source_path)
//////////////////////////////////////////////////////////////////////
collada::effect::load_effects();
scene_state.load_scene(&shadow_test::descriptor);
scene_state.load_scene(&noodle::descriptor);
node_eye = scene_state.find_node_by_name("Camera001");
assert(node_eye != nullptr);
node_at = scene_state.find_node_by_name("Camera001.Target");