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) it = iter(array.floats)
for i in range(accessor.count): for i in range(accessor.count):
vector = ", ".join(f"{float(f)}f" for f in islice(it, accessor.stride)) 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 f"{{ {vector} }},"
yield "};" yield "};"
else: else:

View File

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

View File

@ -5,17 +5,17 @@ namespace curve_interpolation {
using namespace collada; using namespace collada;
float const array_node_cube_translation_x_input_array[] = { float const array_node_cube_translation_x_input_array[] = {
{ 0.0f }, 0.0f,
{ 1.666667f }, 1.666667f,
{ 3.333333f }, 3.333333f,
{ 5.0f }, 5.0f,
}; };
float const array_node_cube_translation_x_output_array[] = { 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[] = { 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[] = { float const array_node_cube_translation_y_input_array[] = {
{ -0.8333334f }, -0.8333334f,
{ 0.8333334f }, 0.8333334f,
{ 2.5f }, 2.5f,
{ 4.166667f }, 4.166667f,
}; };
float const array_node_cube_translation_y_output_array[] = { float const array_node_cube_translation_y_output_array[] = {
{ -10.05776f }, -10.05776f,
{ 10.05852f }, 10.05852f,
{ -9.941484f }, -9.941484f,
{ 10.05852f }, 10.05852f,
}; };
float2 const array_node_cube_translation_y_intangent_array[] = { 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[] = {}; channel const * const node_channels_node_environmentambientlight[] = {};
node const node_node_environmentambientlight = { node const node_node_environmentambientlight = {
.parent_index = -1,
.type = node_type::NODE, .type = node_type::NODE,
.transforms = transforms_node_environmentambientlight, .transforms = transforms_node_environmentambientlight,
@ -574,11 +576,13 @@ instance_geometry const instance_geometries_node_cube[] = {
}; };
channel const * const node_channels_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_y,
&node_channel_node_cube_translation_x,
}; };
node const node_node_cube = { node const node_node_cube = {
.parent_index = -1,
.type = node_type::NODE, .type = node_type::NODE,
.transforms = transforms_node_cube, .transforms = transforms_node_cube,
@ -613,6 +617,8 @@ channel const * const node_channels_node_cylinder001[] = {
}; };
node const node_node_cylinder001 = { node const node_node_cylinder001 = {
.parent_index = -1,
.type = node_type::NODE, .type = node_type::NODE,
.transforms = transforms_node_cylinder001, .transforms = transforms_node_cylinder001,
@ -655,6 +661,8 @@ channel const * const node_channels_node_plane001[] = {
}; };
node const node_node_plane001 = { node const node_node_plane001 = {
.parent_index = -1,
.type = node_type::NODE, .type = node_type::NODE,
.transforms = transforms_node_plane001, .transforms = transforms_node_plane001,

View File

@ -287,26 +287,26 @@ namespace collada_scene {
{ {
switch (effect.type) { switch (effect.type) {
case effect_type::BLINN: case effect_type::BLINN:
g_pEmissionVariable->SetFloatVector((float *)&effect.blinn.emission.color.x); g_pEmissionVariable->SetFloatVector((float *)&effect.blinn.emission.color);
g_pAmbientVariable->SetFloatVector((float *)&effect.blinn.ambient.color.x); g_pAmbientVariable->SetFloatVector((float *)&effect.blinn.ambient.color);
g_pDiffuseVariable->SetFloatVector((float *)&effect.blinn.diffuse.color.x); g_pDiffuseVariable->SetFloatVector((float *)&effect.blinn.diffuse.color);
g_pSpecularVariable->SetFloatVector((float *)&effect.blinn.specular.color.x); g_pSpecularVariable->SetFloatVector((float *)&effect.blinn.specular.color);
g_pShininessVariable->SetFloat(effect.blinn.shininess); g_pShininessVariable->SetFloat(effect.blinn.shininess);
break; break;
case effect_type::LAMBERT: case effect_type::LAMBERT:
g_pEmissionVariable->SetFloatVector((float *)&effect.lambert.emission.color.x); g_pEmissionVariable->SetFloatVector((float *)&effect.lambert.emission.color);
g_pAmbientVariable->SetFloatVector((float *)&effect.lambert.ambient.color.x); g_pAmbientVariable->SetFloatVector((float *)&effect.lambert.ambient.color);
g_pDiffuseVariable->SetFloatVector((float *)&effect.lambert.diffuse.color.x); g_pDiffuseVariable->SetFloatVector((float *)&effect.lambert.diffuse.color);
break; break;
case effect_type::PHONG: case effect_type::PHONG:
g_pEmissionVariable->SetFloatVector((float *)&effect.phong.emission.color.x); g_pEmissionVariable->SetFloatVector((float *)&effect.phong.emission.color);
g_pAmbientVariable->SetFloatVector((float *)&effect.phong.ambient.color.x); g_pAmbientVariable->SetFloatVector((float *)&effect.phong.ambient.color);
g_pDiffuseVariable->SetFloatVector((float *)&effect.phong.diffuse.color.x); g_pDiffuseVariable->SetFloatVector((float *)&effect.phong.diffuse.color);
g_pSpecularVariable->SetFloatVector((float *)&effect.phong.specular.color.x); g_pSpecularVariable->SetFloatVector((float *)&effect.phong.specular.color);
g_pShininessVariable->SetFloat(effect.phong.shininess); g_pShininessVariable->SetFloat(effect.phong.shininess);
break; break;
case effect_type::CONSTANT: case effect_type::CONSTANT:
g_pEmissionVariable->SetFloatVector((float *)&effect.constant.color.x); g_pEmissionVariable->SetFloatVector((float *)&effect.constant.color);
break; break;
default: default:
break; 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_pViewVariable->SetMatrix((float *)&g_View);
g_pProjectionVariable->SetMatrix((float *)&g_Projection); g_pProjectionVariable->SetMatrix((float *)&g_Projection);
g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
t = loop(t / 2.0f, 3.333333f);
for (int i = 0; i < m_descriptor->nodes_count; i++) { for (int i = 0; i < m_descriptor->nodes_count; i++) {
node const& node = *m_descriptor->nodes[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) if (node.type != node_type::NODE)
continue; 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); render_geometries(node.instance_geometries, node.instance_geometries_count);
} }
} }

View File

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