commit f59764e62ceb9216ba99ef719c73dbffc73c2a46
parent 8299b4b637fefe25e0402929f0ca4e140ae4cf21
Author: Michael Savage <mikejsavage@gmail.com>
Date: Wed, 17 Jul 2019 14:25:31 +0300
GLTF fixes
Diffstat:
2 files changed, 126 insertions(+), 34 deletions(-)
diff --git a/gltf.cc b/gltf.cc
@@ -124,20 +124,49 @@ void SampleAnimationClip( const AnimationReel & reel, u32 clip_idx, float t, flo
local_time = clamp( 0.0f, t - start_time, clip.duration );
}
- for( u32 i = 0; i < reel.num_joints; i++ ) {
- const AnimationReel::Joint & joint = reel.joints[ i ];
+ for( u8 i = 0; i < reel.num_joints; i++ ) {
+ joint_poses[ i ].rotation = quat_identity();
+ joint_poses[ i ].translation = Vec3( 0 );
+ joint_poses[ i ].scale = 1.0f;
- u32 rotation_sample, translation_sample, scale_sample;
- float rotation_lerp_frac, translation_lerp_frac, scale_lerp_frac;
+ const AnimationReel::Joint & joint = reel.joints[ i ];
- SampleAnimationChannel( joint.rotations.times, joint.rotations.num_samples, local_time, &rotation_sample, &rotation_lerp_frac );
- SampleAnimationChannel( joint.translations.times, joint.translations.num_samples, local_time, &translation_sample, &translation_lerp_frac );
- SampleAnimationChannel( joint.scales.times, joint.scales.num_samples, local_time, &scale_sample, &scale_lerp_frac );
+ if( joint.rotations.samples != NULL ) {
+ if( joint.rotations.num_samples == 1 ) {
+ joint_poses[ i ].rotation = joint.rotations.samples[ 0 ];
+ }
+ else {
+ u32 sample;
+ float lerp_frac;
+ SampleAnimationChannel( joint.rotations.times, joint.rotations.num_samples, local_time, &sample, &lerp_frac );
+ joint_poses[ i ].rotation = NLerp( joint.rotations.samples[ sample ], lerp_frac, joint.rotations.samples[ ( sample + 1 ) % joint.rotations.num_samples ] );
+ }
+ }
- joint_poses[ i ].rotation = NLerp( joint.rotations.samples[ rotation_sample ], rotation_lerp_frac, joint.rotations.samples[ ( rotation_sample + 1 ) % joint.rotations.num_samples ] );
- joint_poses[ i ].translation = Lerp( joint.translations.samples[ translation_sample ], translation_lerp_frac, joint.translations.samples[ ( translation_sample + 1 ) % joint.translations.num_samples ] );
- joint_poses[ i ].scale = Lerp( joint.scales.samples[ scale_sample ], scale_lerp_frac, joint.scales.samples[ ( scale_sample + 1 ) % joint.scales.num_samples ] );
- }
+ if( joint.translations.samples != NULL ) {
+ if( joint.translations.num_samples == 1 ) {
+ joint_poses[ i ].translation = joint.translations.samples[ 0 ];
+ }
+ else {
+ u32 sample;
+ float lerp_frac;
+ SampleAnimationChannel( joint.translations.times, joint.translations.num_samples, local_time, &sample, &lerp_frac );
+ joint_poses[ i ].translation = Lerp( joint.translations.samples[ sample ], lerp_frac, joint.translations.samples[ ( sample + 1 ) % joint.translations. num_samples ] );
+ }
+ }
+
+ if( joint.scales.samples != NULL ) {
+ if( joint.scales.num_samples == 1 ) {
+ joint_poses[ i ].scale = joint.scales.samples[ 0 ];
+ }
+ else {
+ u32 sample;
+ float lerp_frac;
+ SampleAnimationChannel( joint.scales.times, joint.scales.num_samples, local_time, &sample, &lerp_frac );
+ joint_poses[ i ].scale = Lerp( joint.scales.samples[ sample ], lerp_frac, joint.scales.samples[ ( sample + 1 ) % joint.scales.num_samples ] );
+ }
+ }
+ }
}
void ComputeMatrixPalette( const AnimationReel & animation, const SQT * sqts, Mat4 * joint_poses, Mat4 * skinning_matrices ) {
@@ -202,6 +231,7 @@ static void AddJoint( const cgltf_skin * skin, cgltf_node * node, u8 ** prev ) {
static void LoadSkin( const cgltf_skin * skin ) {
model.animation.joints = ( AnimationReel::Joint * ) malloc( sizeof( AnimationReel::Joint ) * skin->joints_count );
model.animation.num_joints = skin->joints_count;
+ memset( model.animation.joints, 0, sizeof( AnimationReel::Joint ) * skin->joints_count );
for( size_t i = 0; i < skin->joints_count; i++ ) {
skin->joints[ i ]->camera = ( cgltf_camera * ) ( i + 1 );
@@ -210,6 +240,7 @@ static void LoadSkin( const cgltf_skin * skin ) {
u8 * prev_ptr = &model.animation.root_joint;
for( size_t i = 0; i < skin->joints_count; i++ ) {
if( skin->joints[ i ]->parent == NULL || skin->joints[ i ]->parent->camera == NULL ) {
+ ggprint( "root {}\n", skin->joints[ i ]->name );
AddJoint( skin, skin->joints[ i ], &prev_ptr );
}
}
@@ -273,12 +304,15 @@ static void LoadAnimationReel( MemoryArena * arena, const cgltf_animation * anim
u8 joint_idx = u8( uintptr_t( chan->target_node->camera ) - 1 );
if( chan->target_path == cgltf_animation_path_type_translation ) {
+ ggprint( "{} translation\n", chan->target_node->name );
LoadChannel( chan, &model.animation.joints[ joint_idx ].translations );
}
else if( chan->target_path == cgltf_animation_path_type_rotation ) {
+ ggprint( "{} rotation\n", chan->target_node->name );
LoadChannel( chan, &model.animation.joints[ joint_idx ].rotations );
}
else if( chan->target_path == cgltf_animation_path_type_scale ) {
+ ggprint( "{} scale\n", chan->target_node->name );
LoadScaleChannel( chan, &model.animation.joints[ joint_idx ].scales );
}
else {
@@ -286,6 +320,19 @@ static void LoadAnimationReel( MemoryArena * arena, const cgltf_animation * anim
}
}
+ ggprint( "num channels {}\n", animation->channels_count );
+ for( size_t i = 0; i < animation->channels_count; i++ ) {
+ const cgltf_animation_channel * chan = &animation->channels[ i ];
+
+ ASSERT( chan->target_node->camera != NULL );
+ u8 joint_idx = u8( uintptr_t( chan->target_node->camera ) - 1 );
+
+ const AnimationReel::Joint & joint = model.animation.joints[ joint_idx ];
+ if( joint.translations.samples == NULL ) {
+ ggprint( "{} no translation channel\n", chan->target_node->name );
+ }
+ }
+
CLIP.start_time = 0;
CLIP.duration = 10;
CLIP.loop = true;
@@ -294,6 +341,42 @@ static void LoadAnimationReel( MemoryArena * arena, const cgltf_animation * anim
model.animation.num_clips = 1;
}
+template< typename T, size_t N >
+static void CreateSingleSampleChannel( AnimationReel::Channel< T > * out_channel, const float ( &sample )[ N ] ) {
+ constexpr size_t lanes = sizeof( T ) / sizeof( float );
+ STATIC_ASSERT( lanes == N );
+
+ float * memory = ( float * ) malloc( ( N + 1 ) * sizeof( float ) );
+ out_channel->times = memory;
+ out_channel->samples = ( T * ) ( memory + 1 );
+ out_channel->num_samples = 1;
+
+ out_channel->times[ 0 ] = 0.0f;
+ memcpy( &out_channel->samples[ 0 ], sample, N * sizeof( float ) );
+}
+
+static void FixupMissingAnimationChannels( const cgltf_skin * skin ) {
+ for( u8 i = 0; i < model.animation.num_joints; i++ ) {
+ const cgltf_node * node = skin->joints[ i ];
+ AnimationReel::Joint & joint = model.animation.joints[ i ];
+
+ if( joint.rotations.samples == NULL && node->has_rotation ) {
+ CreateSingleSampleChannel( &joint.rotations, node->rotation );
+ }
+
+ if( joint.translations.samples == NULL && node->has_translation ) {
+ CreateSingleSampleChannel( &joint.translations, node->translation );
+ }
+
+ if( joint.scales.samples == NULL && node->has_scale ) {
+ ASSERT( fabsf( node->scale[ 0 ] / node->scale[ 1 ] - 1.0f ) < 0.001f );
+ ASSERT( fabsf( node->scale[ 0 ] / node->scale[ 2 ] - 1.0f ) < 0.001f );
+ float scale[ 1 ] = { node->scale[ 0 ] };
+ CreateSingleSampleChannel( &joint.scales, scale );
+ }
+ }
+}
+
array< const u8 > AccessorToSpan( const cgltf_accessor * accessor ) {
cgltf_size offset = accessor->offset + accessor->buffer_view->offset;
return array< const u8 >( ( const u8 * ) accessor->buffer_view->buffer->data + offset, accessor->count * accessor->stride );
@@ -304,15 +387,7 @@ static void LoadNode( MemoryArena * arena, const cgltf_node * node, bool animate
Mat4 transform;
{
- const Mat4 y_up_to_z_up = Mat4(
- 1, 0, 0, 0,
- 0, 0, 1, 0,
- 0, 1, 0, 0,
- 0, 0, 0, 1
- );
-
cgltf_node_transform_local( node, transform.ptr() );
- // transform = y_up_to_z_up * transform;
}
for( size_t i = 0; i < node->children_count; i++ ) {
@@ -322,10 +397,6 @@ static void LoadNode( MemoryArena * arena, const cgltf_node * node, bool animate
if( node->mesh == NULL )
return;
- if( node->skin != NULL ) {
- LoadSkin( node->skin );
- }
-
ASSERT( node->mesh->primitives_count == 1 );
const cgltf_primitive & prim = node->mesh->primitives[ 0 ];
@@ -388,7 +459,7 @@ GAME_INIT( game_init ) {
cgltf_options options = { };
cgltf_data * data;
- if( cgltf_parse_file( &options, "bigvic.glb", &data ) != cgltf_result_success )
+ if( cgltf_parse_file( &options, "padporknoesis.glb", &data ) != cgltf_result_success )
FATAL( "cgltf_parse_file" );
if( cgltf_load_buffers( &options, data, "./" ) != cgltf_result_success )
FATAL( "cgltf_load_buffers" );
@@ -399,6 +470,7 @@ GAME_INIT( game_init ) {
ASSERT( data->animations_count <= 1 );
ASSERT( data->skins_count <= 1 );
+ ASSERT( data->animations_count == data->skins_count );
ASSERT( data->cameras_count == 0 );
model.num_meshes = 0;
@@ -408,7 +480,9 @@ GAME_INIT( game_init ) {
}
if( data->animations_count > 0 ) {
+ LoadSkin( &data->skins[ 0 ] );
LoadAnimationReel( &mem->persistent_arena, &data->animations[ 0 ] );
+ FixupMissingAnimationChannels( &data->skins[ 0 ] );
}
cgltf_free( data );
@@ -418,6 +492,7 @@ GAME_INIT( game_init ) {
game->pos = v3( -10, -10, 5 );
game->pitch = 0;
game->yaw = 45;
+ game->sun_angle = 0;
}
GAME_FRAME( game_frame ) {
@@ -431,6 +506,10 @@ GAME_FRAME( game_frame ) {
float dpitch = float( input->keys[ KEY_DOWNARROW ] - input->keys[ KEY_UPARROW ] );
float dyaw = float( input->keys[ KEY_LEFTARROW ] - input->keys[ KEY_RIGHTARROW ] );
+ float dsun = ( input->keys[ KEY_EQUALS ] * input->key_edges[ KEY_EQUALS ] - input->keys[ KEY_MINUS ] * input->key_edges[ KEY_MINUS ] ) * 0.01666f;
+ dsun += input->keys[ KEY_T ] * 0.01666f;
+ game->sun_angle += dsun;
+
dpitch += input->keys[ KEY_K ] - input->keys[ KEY_I ];
dyaw += input->keys[ KEY_J ] - input->keys[ KEY_L ];
@@ -446,11 +525,18 @@ GAME_FRAME( game_frame ) {
game->pos += right * dt * lr * speed;
game->pos.z += dt * dz * speed;
- const m4 P = m4_perspective( 90, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH );
+ m4 P = m4_perspective( 90, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH );
m4 V = m4_view( forward, right, up, game->pos );
+ m4 y_up_to_z_up = m4(
+ 1, 0, 0, 0,
+ 0, 0, -1, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1
+ );
+
SQT sample_sqt[ 100 ];
- SampleAnimationClip( model.animation, 0, current_time, 0.0f, sample_sqt );
+ SampleAnimationClip( model.animation, 0, game->sun_angle, 0.0f, sample_sqt );
Mat4 joint_matrices[ 100 ];
Mat4 skinning_matrices[ 100 ];
@@ -460,6 +546,7 @@ GAME_FRAME( game_frame ) {
renderer_begin_pass( RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO );
UniformBinding view_uniforms = renderer_uniforms( V, P, game->pos );
+ UniformBinding model_uniforms = renderer_uniforms( y_up_to_z_up );
UniformBinding joints_uniforms = renderer_upload_uniforms( skinning_matrices, model.animation.num_joints * sizeof( Mat4 ), 16 );
if( !input->keys[ KEY_LEFTCTRL ] ) {
@@ -468,6 +555,7 @@ GAME_FRAME( game_frame ) {
RenderState render_state;
render_state.shader = get_shader( SHADER_SKINNED_FLAT_VERTEX_COLOURS );
render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms;
+ render_state.uniforms[ UNIFORMS_MODEL ] = model_uniforms;
render_state.uniforms[ UNIFORMS_JOINT_POSES ] = joints_uniforms;
render_state.textures[ 0 ] = renderer_blue_noise();
render_state.wireframe = input->keys[ KEY_M ];
@@ -480,8 +568,8 @@ GAME_FRAME( game_frame ) {
// draw an arrow on the guy's head
{
u8 head_joint = 4;
- v3 pos = ( joint_matrices[ head_joint ] * v4( 0, 0, 0, 1 ) ).xyz();
- v3 up = ( joint_matrices[ head_joint ] * v4( 0, 1, 0, 0 ) ).xyz();
+ v3 pos = ( y_up_to_z_up * joint_matrices[ head_joint ] * v4( 0, 0, 0, 1 ) ).xyz();
+ v3 up = ( y_up_to_z_up * joint_matrices[ head_joint ] * v4( 0, 1, 0, 0 ) ).xyz();
immediate_arrow( pos, up, 1, v4( 0, 1, 0, 1 ) );
@@ -494,12 +582,12 @@ GAME_FRAME( game_frame ) {
else {
// draw skeleton
for( u32 i = 0; i < model.animation.num_joints; i++ ) {
- v3 pos = ( joint_matrices[ i ] * v4( 0, 0, 0, 1 ) ).xyz();
- v3 parent_pos = ( joint_matrices[ model.animation.joints[ i ].parent ] * v4( 0, 0, 0, 1 ) ).xyz();
+ v3 pos = ( y_up_to_z_up * joint_matrices[ i ] * v4( 0, 0, 0, 1 ) ).xyz();
+ v3 parent_pos = ( y_up_to_z_up * joint_matrices[ model.animation.joints[ i ].parent ] * v4( 0, 0, 0, 1 ) ).xyz();
- immediate_sphere( pos, 0.025, v4( 1 ) );
- immediate_arrow( pos, joint_matrices[ i ].col1.xyz(), 0.2, v4( 0.5, 0.5, 0.5, 1 ) );
- immediate_arrow( pos, joint_matrices[ i ].col0.xyz(), 0.2, v4( 0, 0, 1, 1 ) );
+ immediate_sphere( pos, 1.0, v4( 1 ) );
+ immediate_arrow( pos, ( y_up_to_z_up * joint_matrices[ i ].col1 ).xyz(), 5.0, v4( 0.5, 0.5, 0.5, 1 ) );
+ immediate_arrow( pos, ( y_up_to_z_up * joint_matrices[ i ].col0 ).xyz(), 5.0, v4( 0, 0, 1, 1 ) );
if( i != 0 )
immediate_arrow( pos, ( parent_pos - pos ), 0.1, v4( 1, 0, 0, 1 ) );
}
diff --git a/shaders/skinned_flat_vertex_colours.glsl b/shaders/skinned_flat_vertex_colours.glsl
@@ -13,6 +13,10 @@ layout( std140 ) uniform view {
mat4 P;
};
+layout( std140 ) uniform model {
+ mat4 M;
+};
+
layout( std140 ) uniform animation {
mat4 joint_poses[ 100 ];
};
@@ -24,7 +28,7 @@ void main() {
weights.z * joint_poses[ joints.z ] +
weights.w * joint_poses[ joints.w ];
- gl_Position = P * V * skin * position;
+ gl_Position = P * V * M * skin * position;
frag_colour = colour;
}