collada_scene: linear interpolation

This commit is contained in:
Zack Buhman 2026-01-27 14:43:45 -06:00
parent e4bb6c2616
commit b0906ecdc6
5 changed files with 130 additions and 41 deletions

View File

@ -525,6 +525,9 @@ def render_array(state, collada, accessor, array):
it = iter(array.floats)
for i in range(accessor.count):
vector = ", ".join(f"{float(f)}f" for f in islice(it, accessor.stride))
if accessor.stride == 1:
yield f"{vector},"
else:
yield f"{{ {vector} }},"
yield "};"
else:

View File

@ -24,6 +24,7 @@ namespace collada_scene {
struct node_instance {
transform * transforms = NULL;
XMMATRIX world;
};
struct scene_state {
@ -41,7 +42,7 @@ namespace collada_scene {
collada::descriptor const * m_descriptor;
HRESULT load_scene(collada::descriptor const * const descriptor);
void render();
void render(float t);
private:
HRESULT load_layouts();
@ -51,6 +52,7 @@ namespace collada_scene {
void render_geometries(collada::instance_geometry const * const instance_geometries,
int const instance_geometries_count);
void node_world_transform(collada::node const& node, node_instance& node_instance);
};
HRESULT LoadEffect();

View File

@ -5,17 +5,17 @@ namespace curve_interpolation {
using namespace collada;
float const array_node_cube_translation_x_input_array[] = {
{ 0.0f },
{ 1.666667f },
{ 3.333333f },
{ 5.0f },
0.0f,
1.666667f,
3.333333f,
5.0f,
};
float const array_node_cube_translation_x_output_array[] = {
{ 10.0f },
{ -10.0f },
{ 10.0f },
{ -10.0f },
10.0f,
-10.0f,
10.0f,
-10.0f,
};
float2 const array_node_cube_translation_x_intangent_array[] = {
@ -68,17 +68,17 @@ sampler const sampler_node_cube_translation_x_sampler = {
};
float const array_node_cube_translation_y_input_array[] = {
{ -0.8333334f },
{ 0.8333334f },
{ 2.5f },
{ 4.166667f },
-0.8333334f,
0.8333334f,
2.5f,
4.166667f,
};
float const array_node_cube_translation_y_output_array[] = {
{ -10.05776f },
{ 10.05852f },
{ -9.941484f },
{ 10.05852f },
-10.05776f,
10.05852f,
-9.941484f,
10.05852f,
};
float2 const array_node_cube_translation_y_intangent_array[] = {
@ -519,6 +519,8 @@ instance_geometry const instance_geometries_node_environmentambientlight[] = {
channel const * const node_channels_node_environmentambientlight[] = {};
node const node_node_environmentambientlight = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_environmentambientlight,
@ -574,11 +576,13 @@ instance_geometry const instance_geometries_node_cube[] = {
};
channel const * const node_channels_node_cube[] = {
&node_channel_node_cube_translation_x,
&node_channel_node_cube_translation_y,
&node_channel_node_cube_translation_x,
};
node const node_node_cube = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_cube,
@ -613,6 +617,8 @@ channel const * const node_channels_node_cylinder001[] = {
};
node const node_node_cylinder001 = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_cylinder001,
@ -655,6 +661,8 @@ channel const * const node_channels_node_plane001[] = {
};
node const node_node_plane001 = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_plane001,

View File

@ -287,26 +287,26 @@ namespace collada_scene {
{
switch (effect.type) {
case effect_type::BLINN:
g_pEmissionVariable->SetFloatVector((float *)&effect.blinn.emission.color.x);
g_pAmbientVariable->SetFloatVector((float *)&effect.blinn.ambient.color.x);
g_pDiffuseVariable->SetFloatVector((float *)&effect.blinn.diffuse.color.x);
g_pSpecularVariable->SetFloatVector((float *)&effect.blinn.specular.color.x);
g_pEmissionVariable->SetFloatVector((float *)&effect.blinn.emission.color);
g_pAmbientVariable->SetFloatVector((float *)&effect.blinn.ambient.color);
g_pDiffuseVariable->SetFloatVector((float *)&effect.blinn.diffuse.color);
g_pSpecularVariable->SetFloatVector((float *)&effect.blinn.specular.color);
g_pShininessVariable->SetFloat(effect.blinn.shininess);
break;
case effect_type::LAMBERT:
g_pEmissionVariable->SetFloatVector((float *)&effect.lambert.emission.color.x);
g_pAmbientVariable->SetFloatVector((float *)&effect.lambert.ambient.color.x);
g_pDiffuseVariable->SetFloatVector((float *)&effect.lambert.diffuse.color.x);
g_pEmissionVariable->SetFloatVector((float *)&effect.lambert.emission.color);
g_pAmbientVariable->SetFloatVector((float *)&effect.lambert.ambient.color);
g_pDiffuseVariable->SetFloatVector((float *)&effect.lambert.diffuse.color);
break;
case effect_type::PHONG:
g_pEmissionVariable->SetFloatVector((float *)&effect.phong.emission.color.x);
g_pAmbientVariable->SetFloatVector((float *)&effect.phong.ambient.color.x);
g_pDiffuseVariable->SetFloatVector((float *)&effect.phong.diffuse.color.x);
g_pSpecularVariable->SetFloatVector((float *)&effect.phong.specular.color.x);
g_pEmissionVariable->SetFloatVector((float *)&effect.phong.emission.color);
g_pAmbientVariable->SetFloatVector((float *)&effect.phong.ambient.color);
g_pDiffuseVariable->SetFloatVector((float *)&effect.phong.diffuse.color);
g_pSpecularVariable->SetFloatVector((float *)&effect.phong.specular.color);
g_pShininessVariable->SetFloat(effect.phong.shininess);
break;
case effect_type::CONSTANT:
g_pEmissionVariable->SetFloatVector((float *)&effect.constant.color.x);
g_pEmissionVariable->SetFloatVector((float *)&effect.constant.color);
break;
default:
break;
@ -340,26 +340,102 @@ namespace collada_scene {
}
}
void scene_state::render()
static inline float fract(float f)
{
return f - floorf(f);
}
static inline float loop(float f, float n)
{
return fract(f / n) * n;
}
static inline int find_frame_ix(source const& source, float t)
{
for (int i = 0; i < source.count - 1; i++) {
if (source.float_array[i] <= t && source.float_array[i+1] > t) {
return i;
}
}
return -1;
}
static inline float interpolation_value(source const& source, int ix, float t)
{
float prev = source.float_array[ix];
float next = source.float_array[ix+1];
return (t - prev) / (next - prev);
}
static inline float linear_interpolate(source const& source, int ix, float iv)
{
float prev = source.float_array[ix];
float next = source.float_array[ix+1];
return prev + iv * (next - prev);
}
static void animate_node(node const& node, node_instance& node_instance, float t)
{
for (int i = 0; i < node.channels_count; i++) {
channel const& channel = *node.channels[i];
transform& transform = node_instance.transforms[channel.target_transform_index];
int frame_ix = find_frame_ix(channel.source_sampler->input, t);
if (frame_ix < 0)
continue; // animation is missing a key frame
float iv = interpolation_value(channel.source_sampler->input, frame_ix, t);
float value = linear_interpolate(channel.source_sampler->output, frame_ix, iv);
switch (transform.type) {
case transform_type::TRANSLATE:
switch (channel.target_attribute) {
case target_attribute::X: transform.translate = XMVectorSetX(transform.translate, value); break;
case target_attribute::Y: transform.translate = XMVectorSetY(transform.translate, value); break;
case target_attribute::Z: transform.translate = XMVectorSetZ(transform.translate, value); break;
default: break;
}
break;
default:
break;
}
}
}
void scene_state::node_world_transform(node const& node, node_instance& node_instance)
{
// build the node's world transform matrix
if (node.parent_index >= 0)
node_instance.world = m_nodeInstances[node.parent_index].world;
else
node_instance.world = XMMatrixIdentity();
for (int j = 0; j < node.transforms_count; j++) {
node_instance.world = TransformMatrix(node_instance.transforms[j]) * node_instance.world;
}
}
void scene_state::render(float t)
{
g_pViewVariable->SetMatrix((float *)&g_View);
g_pProjectionVariable->SetMatrix((float *)&g_Projection);
g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
t = loop(t / 2.0f, 3.333333f);
for (int i = 0; i < m_descriptor->nodes_count; i++) {
node const& node = *m_descriptor->nodes[i];
node_instance& node_instance = m_nodeInstances[i];
animate_node(node, node_instance, t);
node_world_transform(node, node_instance);
g_pWorldVariable->SetMatrix((float *)&node_instance.world);
// joints aren't rendered
if (node.type != node_type::NODE)
continue;
node_instance const& node_instance = m_nodeInstances[i];
XMMATRIX World = XMMatrixIdentity();
// build the world transform
for (int j = 0; j < node.transforms_count; j++) {
World = TransformMatrix(node_instance.transforms[j]) * World;
}
g_pWorldVariable->SetMatrix((float *)&World);
render_geometries(node.instance_geometries, node.instance_geometries_count);
}
}

View File

@ -1843,7 +1843,7 @@ void Render(float t, float dt)
//collada::Render(t);
g_SceneState.render();
g_SceneState.render(t);
RenderFont(dt);