Make character run

- new, less blocky character model with a run animation
- remove .obj support in favor of .glb/.gltf
- character faces camera direction and turns head
- press Tab to rotate camera freely around the character
This commit is contained in:
var
2026-04-26 22:21:58 -05:00
parent 839a9dd5c2
commit 0f38e9b4a2
10 changed files with 71 additions and 561 deletions

View File

@@ -334,18 +334,39 @@ static void Transform(ShapeInstance *instance, mat4 *matrix)
static void DrawModel(GameState *gs)
{
Model model = gs->testModel;
ShapeInstance instance = model.instance;
cgltf_data *data = model.data;
cgltf_skin *skin = model.skin;
Model *model = &gs->testModel;
ShapeInstance instance = model->instance;
cgltf_data *data = model->data;
cgltf_skin *skin = model->skin;
cgltf_animation *anim = data->animations;
mat4 modelMatrix;
glm_mat4_identity(modelMatrix);
Transform(&model.instance, &modelMatrix);
uint64_t ticks = SDL_GetTicks();
if (!gs->input.freeLook)
{
// rotate the whole model to stay within this angle relative to the camera yaw
const float turnThreshold = 1.047197f; // 60 degrees
const float deg180 = 3.14159f;
const float deg360 = 6.28318f;
// convert camera yaw (rotation around Y axis) to radians and add 90 degrees so it aligns with the gltf model
float camYawRadsGltf = (gs->camera.rotation[0] / -57.295828f) + 1.570795f;
if (camYawRadsGltf > deg180) camYawRadsGltf = camYawRadsGltf - deg360;
float *modelYaw = model->instance.rotation + 1;
float diff = camYawRadsGltf - *modelYaw;
if (diff > deg180) diff -= deg360;
else if (diff < -deg180) diff += deg360;
if (turnThreshold < diff)
*modelYaw = camYawRadsGltf - turnThreshold;
else if (diff < -turnThreshold)
*modelYaw = camYawRadsGltf + turnThreshold;
}
Transform(&model->instance, &modelMatrix);
uint64_t ticks = SDL_GetTicks64();
float t = ticks / 1000.0f;
while (t > 2.0f) t -= 2.0f;
while (t > 1.0f) t -= 1.0f;
// apply local transformations for each bone for the current animation frame
for (int i = 0; i < anim->channels_count; i++)
@@ -415,14 +436,34 @@ static void DrawModel(GameState *gs)
}
}
if (!gs->input.freeLook)
{
// make head look where camera is looking
cgltf_node *head = model->head;
vec3 a, b, yAxis;
glm_vec3_zero(a);
glm_vec3_zero(b);
glm_vec3_zero(yAxis);
yAxis[1] = 1.0f;
a[2] = 1.0f;
glm_vec3_rotate(a, model->instance.rotation[1], yAxis);
b[0] = gs->camera.front[0];
b[2] = gs->camera.front[2];
versor desiredRotation, temp;
glm_quat_from_vecs(a, b, desiredRotation);
for (int i = 0; i < 4; i++) temp[i] = head->rotation[i];
glm_quat_mul(temp, desiredRotation, temp);
for (int i = 0; i < 4; i++) head->rotation[i] = temp[i];
}
// recalculate the joint matrices
for (int i = 0; i < skin->joints_count; i++)
{
cgltf_node *joint = skin->joints[i];
cgltf_node_transform_world(joint, (float*)model.jointMatrices[i]);
cgltf_node_transform_world(joint, (float*)model->jointMatrices[i]);
mat4 inverseBind;
cgltf_accessor_read_float(skin->inverse_bind_matrices, i, (float*)inverseBind, 16);
glm_mat4_mul(model.jointMatrices[i], inverseBind, model.jointMatrices[i]);
glm_mat4_mul(model->jointMatrices[i], inverseBind, model->jointMatrices[i]);
}
int shaderId = gs->modelShaderProgramId;
@@ -430,12 +471,12 @@ static void DrawModel(GameState *gs)
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theModelMatrix"), 1, GL_FALSE, (void*)(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theViewMatrix"), 1, GL_FALSE, (void*)(gs->viewMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theProjMatrix"), 1, GL_FALSE, (void*)(gs->projMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theJointMatrices"), 64, GL_FALSE, (void*)(model.jointMatrices));
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theJointMatrices"), 64, GL_FALSE, (void*)(model->jointMatrices));
glUniform1f(glGetUniformLocation(shaderId, "texIndex"), 6.0f);
glBindTexture(GL_TEXTURE_2D, gs->textureId);
glBindVertexArray(model.vao);
glDrawElements(GL_TRIANGLES, model.indexCount, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(model->vao);
glDrawElements(GL_TRIANGLES, model->indexCount, GL_UNSIGNED_SHORT, 0);
}
void Render_Draw(GameState *gs)