collada: animated book

This commit is contained in:
Zack Buhman 2026-03-17 17:46:29 -05:00
parent f4e95aee09
commit 2b379aa27c
12 changed files with 4677 additions and 29 deletions

View File

@ -43,7 +43,8 @@ OBJS = \
src/collada/animate.o \ src/collada/animate.o \
data/scenes/ship20/ship20.o \ data/scenes/ship20/ship20.o \
data/scenes/noodle/noodle.o \ data/scenes/noodle/noodle.o \
data/scenes/shadow_test/shadow_test.o data/scenes/shadow_test/shadow_test.o \
data/scenes/book/book.o
all: test.so all: test.so

View File

@ -21,3 +21,15 @@ PYTHONPATH=~/d3d10 python -m collada.main \
PYTHONPATH=~/d3d10 python -m collada.main \ PYTHONPATH=~/d3d10 python -m collada.main \
include/data/scenes/shadow_test.h include/data/scenes/shadow_test.h
# book
PYTHONPATH=~/d3d10 python -m collada.main \
~/Downloads/book.DAE \
data/scenes/book/book.cpp \
data/scenes/book/book.vtx \
data/scenes/book/book.vjw \
data/scenes/book/book.idx
PYTHONPATH=~/d3d10 python -m collada.main \
include/data/scenes/book.h

4616
data/scenes/book/book.cpp Normal file

File diff suppressed because it is too large Load Diff

BIN
data/scenes/book/book.idx Normal file

Binary file not shown.

BIN
data/scenes/book/book.vjw Normal file

Binary file not shown.

BIN
data/scenes/book/book.vtx Normal file

Binary file not shown.

View File

@ -260,6 +260,7 @@ namespace collada::types {
struct skin { struct skin {
types::geometry const * const geometry; // source types::geometry const * const geometry; // source
matrix const bind_shape_matrix; // one per skin
matrix const * const inverse_bind_matrices; // one per joint matrix const * const inverse_bind_matrices; // one per joint
int const vertex_buffer_offset; int const vertex_buffer_offset;

View File

@ -0,0 +1,3 @@
namespace book {
extern collada::types::descriptor const descriptor;
}

View File

@ -7,27 +7,32 @@
namespace collada::animate { namespace collada::animate {
static inline int find_frame_ix(types::source const& source, float t) struct frame_ix {
int f0;
int f1;
};
static inline frame_ix find_frame_ix(types::source const& source, float t)
{ {
for (int i = 0; i < source.count - 1; i++) { for (int i = 0; i < source.count - 1; i++) {
if (source.float_array[i] <= t && source.float_array[i+1] > t) { if (source.float_array[i] <= t && source.float_array[i+1] > t) {
return i; return {i, i + 1};
} }
} }
return -1; return {source.count - 1, 0};
} }
static inline float linear_interpolate_iv(types::source const& source, int frame_ix, float t) static inline float linear_interpolate_iv(types::source const& source, frame_ix frame_ix, float t)
{ {
float prev = source.float_array[(frame_ix+0) * source.stride]; float prev = source.float_array[(frame_ix.f0) * source.stride];
float next = source.float_array[(frame_ix+1) * source.stride]; float next = source.float_array[(frame_ix.f1) * source.stride];
return (t - prev) / (next - prev); return (t - prev) / (next - prev);
} }
static inline float linear_interpolate_value(types::source const& source, int frame_ix, int parameter_ix, float iv) static inline float linear_interpolate_value(types::source const& source, frame_ix frame_ix, int parameter_ix, float iv)
{ {
float prev = source.float_array[(frame_ix+0) * source.stride + parameter_ix]; float prev = source.float_array[(frame_ix.f0) * source.stride + parameter_ix];
float next = source.float_array[(frame_ix+1) * source.stride + parameter_ix]; float next = source.float_array[(frame_ix.f1) * source.stride + parameter_ix];
return prev + iv * (next - prev); return prev + iv * (next - prev);
} }
@ -88,7 +93,7 @@ namespace collada::animate {
return (XMFLOAT2 const *)&source.float_array[ix]; return (XMFLOAT2 const *)&source.float_array[ix];
} }
static float bezier_sampler(types::sampler const * const sampler, int frame_ix, int parameter_ix, float t) static float bezier_sampler(types::sampler const * const sampler, frame_ix frame_ix, int parameter_ix, float t)
{ {
/* /*
P0 is (INPUT[i] , OUTPUT[i]) P0 is (INPUT[i] , OUTPUT[i])
@ -97,15 +102,15 @@ namespace collada::animate {
P1 is (INPUT[i+1], OUTPUT[i+1]) P1 is (INPUT[i+1], OUTPUT[i+1])
*/ */
float frame0_input = sampler->input.float_array[frame_ix+0]; float frame0_input = sampler->input.float_array[frame_ix.f0];
float frame1_input = sampler->input.float_array[frame_ix+1]; float frame1_input = sampler->input.float_array[frame_ix.f1];
float frame0_output = sampler->output.float_array[(frame_ix+0) * sampler->output.stride + parameter_ix]; float frame0_output = sampler->output.float_array[(frame_ix.f0) * sampler->output.stride + parameter_ix];
float frame1_output = sampler->output.float_array[(frame_ix+1) * sampler->output.stride + parameter_ix]; float frame1_output = sampler->output.float_array[(frame_ix.f1) * sampler->output.stride + parameter_ix];
XMVECTOR p0 = XMVectorSet(frame0_input, frame0_output, 0, 0); XMVECTOR p0 = XMVectorSet(frame0_input, frame0_output, 0, 0);
XMVECTOR c0 = XMLoadFloat2(tangent_index(sampler->out_tangent, frame_ix + 0, parameter_ix)); XMVECTOR c0 = XMLoadFloat2(tangent_index(sampler->out_tangent, frame_ix.f0, parameter_ix));
XMVECTOR c1 = XMLoadFloat2(tangent_index(sampler->in_tangent, frame_ix + 1, parameter_ix)); XMVECTOR c1 = XMLoadFloat2(tangent_index(sampler->in_tangent, frame_ix.f1, parameter_ix));
XMVECTOR p1 = XMVectorSet(frame1_input, frame1_output, 0, 0); XMVECTOR p1 = XMVectorSet(frame1_input, frame1_output, 0, 0);
return bezier_binary_search(p0, c0, c1, p1, t); return bezier_binary_search(p0, c0, c1, p1, t);
@ -153,7 +158,7 @@ namespace collada::animate {
static void animate_channel_segment(types::channel const& channel, static void animate_channel_segment(types::channel const& channel,
instance_types::transform& transform, instance_types::transform& transform,
int frame_ix, float t) frame_ix frame_ix, float t)
{ {
enum types::target_attribute const * target_attributes = &channel.target_attribute; enum types::target_attribute const * target_attributes = &channel.target_attribute;
int target_attributes_count = 1; int target_attributes_count = 1;
@ -176,7 +181,7 @@ namespace collada::animate {
for (int parameter_ix = 0; parameter_ix < target_attributes_count; parameter_ix++) { for (int parameter_ix = 0; parameter_ix < target_attributes_count; parameter_ix++) {
enum types::interpolation interpolation = channel.source_sampler->interpolation.interpolation_array[frame_ix]; enum types::interpolation interpolation = channel.source_sampler->interpolation.interpolation_array[frame_ix.f0];
float value; float value;
if (interpolation == types::interpolation::BEZIER) { if (interpolation == types::interpolation::BEZIER) {
@ -196,8 +201,8 @@ namespace collada::animate {
types::channel const& channel = *node_instance.node->channels[i]; types::channel const& channel = *node_instance.node->channels[i];
instance_types::transform& transform = node_instance.transforms[channel.target_transform_index]; instance_types::transform& transform = node_instance.transforms[channel.target_transform_index];
int frame_ix = find_frame_ix(channel.source_sampler->input, t); frame_ix frame_ix = find_frame_ix(channel.source_sampler->input, t);
assert(frame_ix >= 0); // animation is missing a key frame //assert(frame_ix >= 0); // animation is missing a key frame
animate_channel_segment(channel, transform, frame_ix, t); animate_channel_segment(channel, transform, frame_ix, t);
} }

View File

@ -450,6 +450,8 @@ namespace collada::scene {
types::instance_controller const &instance_controller = instance_controllers[i]; types::instance_controller const &instance_controller = instance_controllers[i];
types::skin const &skin = instance_controller.controller->skin; types::skin const &skin = instance_controller.controller->skin;
XMMATRIX bsm = XMLoadFloat4x4((XMFLOAT4X4*)&skin.bind_shape_matrix);
XMFLOAT4X4 joints[instance_controller.joint_count]; XMFLOAT4X4 joints[instance_controller.joint_count];
int joints_size = (sizeof (joints)); int joints_size = (sizeof (joints));
for (int joint_index = 0; joint_index < instance_controller.joint_count; joint_index++) { for (int joint_index = 0; joint_index < instance_controller.joint_count; joint_index++) {
@ -457,7 +459,7 @@ namespace collada::scene {
int node_index = instance_controller.joint_node_indices[joint_index]; int node_index = instance_controller.joint_node_indices[joint_index];
instance_types::node& node_instance = node_state.node_instances[node_index]; instance_types::node& node_instance = node_state.node_instances[node_index];
XMStoreFloat4x4(&joints[joint_index], ibm * node_instance.world); XMStoreFloat4x4(&joints[joint_index], bsm * ibm * node_instance.world);
} }
glBindBuffer(GL_UNIFORM_BUFFER, joint_uniform_buffer); glBindBuffer(GL_UNIFORM_BUFFER, joint_uniform_buffer);
glBufferData(GL_UNIFORM_BUFFER, joints_size, (void *)&joints[0], GL_DYNAMIC_DRAW); glBufferData(GL_UNIFORM_BUFFER, joints_size, (void *)&joints[0], GL_DYNAMIC_DRAW);
@ -520,7 +522,7 @@ namespace collada::scene {
void state::update(float t) void state::update(float t)
{ {
t = animate::loop(t / 4.0f, 3.333333f); t = animate::loop(t / 4.0f, 1.8333333333333333f);
for (int i = 0; i < descriptor->nodes_count; i++) { for (int i = 0; i < descriptor->nodes_count; i++) {
animate::animate_node(node_state.node_instances[i], t); animate::animate_node(node_state.node_instances[i], t);

View File

@ -29,6 +29,7 @@
#include "data/scenes/ship20.h" #include "data/scenes/ship20.h"
#include "data/scenes/noodle.h" #include "data/scenes/noodle.h"
#include "data/scenes/shadow_test.h" #include "data/scenes/shadow_test.h"
#include "data/scenes/book.h"
struct line_location { struct line_location {
struct { struct {
@ -309,11 +310,13 @@ void load(const char * source_path)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
collada::effect::load_effects(); collada::effect::load_effects();
scene_state.load_scene(&noodle::descriptor); scene_state.load_scene(&book::descriptor);
node_eye = scene_state.find_node_by_name("Camera001"); node_eye = scene_state.find_node_by_name("Camera");
assert(node_eye != nullptr); assert(node_eye != nullptr);
node_at = scene_state.find_node_by_name("Camera001.Target"); //view::state.eye = XMVector3Transform(XMVectorZero(), node_eye->world);
assert(node_at != nullptr);
//node_at = scene_state.find_node_by_name("Camera001.Target");
//assert(node_at != nullptr);
} }
void update_keyboard(int up, int down, int left, int right, void update_keyboard(int up, int down, int left, int right,
@ -453,8 +456,13 @@ void update(float time)
current_time = time; current_time = time;
scene_state.update(time); scene_state.update(time);
/*
view::state.eye = XMVector3Transform(XMVectorZero(), node_eye->world); view::state.eye = XMVector3Transform(XMVectorZero(), node_eye->world);
if (node_at == nullptr)
view::state.at = XMVectorZero();
else
view::state.at = XMVector3Transform(XMVectorZero(), node_at->world); view::state.at = XMVector3Transform(XMVectorZero(), node_at->world);
*/
view::update_transforms(); view::update_transforms();
} }

View File

@ -107,6 +107,6 @@ namespace view {
//state.eye = XMVectorSet(-45.5f, 43.25f, 63.0f, 1); //state.eye = XMVectorSet(-45.5f, 43.25f, 63.0f, 1);
//state.at = state.eye + state.direction * at_distance; //state.at = state.eye + state.direction * at_distance;
state.at = XMVectorSet(0, 0, 0, 1); state.at = XMVectorSet(0, 0, 0, 1);
state.eye = XMVectorSet(0, -10, 0, 1); state.eye = XMVectorSet(0, -100, 0, 1);
} }
} }