medfall

A super great game engine
Log | Files | Refs

commit f59764e62ceb9216ba99ef719c73dbffc73c2a46
parent 8299b4b637fefe25e0402929f0ca4e140ae4cf21
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Wed, 17 Jul 2019 14:25:31 +0300

GLTF fixes

Diffstat:
Mgltf.cc | 154++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mshaders/skinned_flat_vertex_colours.glsl | 6+++++-
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; }