Add player animation blending

This commit is contained in:
James Lambert 2022-12-05 21:54:08 -07:00
parent 46a66b4419
commit 89004dcb4f
11 changed files with 204 additions and 58 deletions

Binary file not shown.

View file

@ -5,6 +5,8 @@
#include "mathf.h"
#include <math.h>
struct Quaternion gQuaternionZero = {0.0f, 0.0f, 0.0f, 0.0f};
void quatIdent(struct Quaternion* q) {
q->x = 0.0f;
q->y = 0.0f;

View file

@ -9,6 +9,8 @@ struct Quaternion {
float x, y, z, w;
};
extern struct Quaternion gQuaternionZero;
void quatIdent(struct Quaternion* q);
void quatAxisAngle(struct Vector3* axis, float angle, struct Quaternion* out);
void quatAxisComplex(struct Vector3* axis, struct Vector2* complex, struct Quaternion* out);

View file

@ -98,9 +98,10 @@ void playerInit(struct Player* player, struct Location* startLocation, struct Ve
collisionSceneAddDynamicObject(&player->collisionObject);
skArmatureInit(&player->armature, &player_chell_armature);
skAnimatorV2Init(&player->animator, player_chell_armature.numberOfBones);
skBlenderInit(&player->animator, player_chell_armature.numberOfBones);
skAnimatorV2RunClip(&player->animator, &player_chell_Armature_runn_clip, 0.0f, SKAnimatorV2FlagsLoop);
skAnimatorRunClip(&player->animator.from, &player_chell_Armature_runn_clip, 0.0f, SKAnimatorFlagsLoop);
skAnimatorRunClip(&player->animator.to, &player_chell_Armature_runc_clip, 0.0f, SKAnimatorFlagsLoop);
player->body.velocity = *velocity;
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
@ -294,11 +295,53 @@ void playerGetMoveBasis(struct Transform* transform, struct Vector3* forward, st
vector3Normalize(right, right);
}
struct SKAnimationClip* playerDetermineNextClip(struct Player* player, float* blendLerp, float* startTime, struct Vector3* forwardDir, struct Vector3* rightDir) {
float horzSpeed = player->body.velocity.x * player->body.velocity.x + player->body.velocity.z * player->body.velocity.z;
if (horzSpeed < 0.0001f) {
*blendLerp = 0.0f;
*startTime = 0.0f;
return &player_chell_Armature_idle_clip;
}
horzSpeed = sqrtf(horzSpeed);
*blendLerp = 1.0f - horzSpeed * (1.0f / PLAYER_SPEED);
if (*blendLerp < 0.0f) {
*blendLerp = 0.0f;
}
if (*blendLerp > 1.0f) {
*blendLerp = 1.0f;
}
*startTime = player->animator.from.currentTime;
float forward = forwardDir->x * player->body.velocity.x + forwardDir->z * player->body.velocity.z;
float right = rightDir->x * player->body.velocity.x + rightDir->z * player->body.velocity.z;
if (fabsf(forward) > fabsf(right)) {
if (forward > 0.0f) {
return &player_chell_Armature_runs_clip;
} else {
return &player_chell_Armature_runn_clip;
}
} else {
if (right > 0.0f) {
return &player_chell_Armature_rune_clip;
} else {
return &player_chell_Armature_runw_clip;
}
}
}
void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
struct Vector3 forward;
struct Vector3 right;
skAnimatorV2Update(&player->animator, player->armature.boneTransforms, FIXED_DELTA_TIME);
skBlenderUpdate(&player->animator, player->armature.boneTransforms, FIXED_DELTA_TIME);
int doorwayMask = worldCheckDoorwaySides(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom);
playerGetMoveBasis(&player->lookTransform, &forward, &right);
@ -448,4 +491,11 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
player->body.currentRoom = worldCheckDoorwayCrossings(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom, doorwayMask);
dynamicSceneSetRoomFlags(player->dynamicId, ROOM_FLAG_FROM_INDEX(player->body.currentRoom));
float startTime = 0.0f;
struct SKAnimationClip* clip = playerDetermineNextClip(player, &player->animator.blendLerp, &startTime, &forward, &right);
if (clip != player->animator.from.currentClip) {
skAnimatorRunClip(&player->animator.from, clip, startTime, SKAnimatorFlagsLoop);
}
}

View file

@ -23,7 +23,7 @@ struct Player {
struct RigidBody body;
struct Transform lookTransform;
struct SKArmature armature;
struct SKAnimatorV2 animator;
struct SKAnimatorBlender animator;
short grabbingThroughPortal;
short dynamicId;
struct CollisionObject* grabbing;

View file

@ -100,7 +100,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def
skArmatureInit(&dropper->armature, &props_box_dropper_armature);
skAnimatorV2Init(&dropper->animator, PROPS_BOX_DROPPER_DEFAULT_BONES_COUNT);
skAnimatorInit(&dropper->animator, PROPS_BOX_DROPPER_DEFAULT_BONES_COUNT);
dropper->flags = 0;
dropper->reloadTimer = DROOPER_RELOAD_TIME;
@ -109,7 +109,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def
}
void boxDropperUpdate(struct BoxDropper* dropper) {
skAnimatorV2Update(&dropper->animator, dropper->armature.boneTransforms, FIXED_DELTA_TIME);
skAnimatorUpdate(&dropper->animator, dropper->armature.boneTransforms, FIXED_DELTA_TIME);
if (dropper->reloadTimer > 0.0f) {
dropper->reloadTimer -= FIXED_DELTA_TIME;
@ -143,7 +143,7 @@ void boxDropperUpdate(struct BoxDropper* dropper) {
boxDropperFakePos(dropper, &pendingCubePos);
decorObjectInit(&dropper->activeCube, decorObjectDefinitionForId(DECOR_TYPE_CUBE), &pendingCubePos, dropper->roomIndex);
skAnimatorV2RunClip(&dropper->animator, &props_box_dropper_Armature_DropCube_clip, 0.0f, 0);
skAnimatorRunClip(&dropper->animator, &props_box_dropper_Armature_DropCube_clip, 0.0f, 0);
dropper->flags &= ~BoxDropperFlagsCubeRequested;
dropper->flags |= BoxDropperFlagsCubeIsActive;

View file

@ -17,7 +17,7 @@ enum BoxDropperFlags {
struct BoxDropper {
struct Transform transform;
struct SKArmature armature;
struct SKAnimatorV2 animator;
struct SKAnimator animator;
struct DecorObject activeCube;
float reloadTimer;

View file

@ -60,7 +60,7 @@ void pedestalInit(struct Pedestal* pedestal, struct PedestalDefinition* definiti
skArmatureInit(&pedestal->armature, &pedestal_armature);
skAnimatorV2Init(&pedestal->animator, PEDESTAL_DEFAULT_BONES_COUNT);
skAnimatorInit(&pedestal->animator, PEDESTAL_DEFAULT_BONES_COUNT);
pedestal->dynamicId = dynamicSceneAdd(pedestal, pedestalRender, &pedestal->transform, 0.8f);
@ -82,7 +82,7 @@ void pedestalDetermineHolderAngle(struct Pedestal* pedestal, struct Vector2* out
}
void pedestalUpdate(struct Pedestal* pedestal) {
skAnimatorV2Update(&pedestal->animator, pedestal->armature.boneTransforms, FIXED_DELTA_TIME);
skAnimatorUpdate(&pedestal->animator, pedestal->armature.boneTransforms, FIXED_DELTA_TIME);
if (pedestal->flags & PedestalFlagsIsPointing) {
struct Vector2 target;
@ -99,7 +99,7 @@ void pedestalUpdate(struct Pedestal* pedestal) {
void pedestalHide(struct Pedestal* pedestal) {
pedestal->flags |= PedestalFlagsDown;
skAnimatorV2RunClip(&pedestal->animator, &pedestal_Armature_Hide_clip, 0.0f, 0);
skAnimatorRunClip(&pedestal->animator, &pedestal_Armature_Hide_clip, 0.0f, 0);
}
void pedestalPointAt(struct Pedestal* pedestal, struct Vector3* target) {

View file

@ -13,7 +13,7 @@ enum PedestalFlags {
struct Pedestal {
struct Transform transform;
struct SKArmature armature;
struct SKAnimatorV2 animator;
struct SKAnimator animator;
short dynamicId;
short roomIndex;

View file

@ -31,7 +31,7 @@ void skAnimatorCopy(u32 romAddress, void* target, u32 size) {
osEPiStartDma(gAnimationPiHandle, ioMesg, OS_READ);
}
void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) {
void skAnimatorInit(struct SKAnimator* animator, int nBones) {
animator->currentClip = NULL;
animator->currentTime = 0.0f;
animator->blendLerp = 0.0f;
@ -43,7 +43,7 @@ void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) {
animator->nBones = nBones;
}
void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) {
void skAnimatorCleanup(struct SKAnimator* animator) {
free(animator->boneState[0]);
free(animator->boneState[1]);
@ -51,7 +51,7 @@ void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) {
animator->boneState[1] = NULL;
}
void skAnimatorV2RequestNext(struct SKAnimatorV2* animator) {
void skAnimatorRequestNext(struct SKAnimator* animator) {
struct SKAnimationClip* currentClip = animator->currentClip;
if (!currentClip) {
@ -77,63 +77,88 @@ void skAnimatorV2RequestNext(struct SKAnimatorV2* animator) {
skAnimatorCopy((u32)currentClip->frames + frameSize * nextFrame, (void*)animator->boneState[animator->latestBoneState], sizeof(struct SKAnimationBoneFrame) * boneCount);
}
void skAnimatorV2Extractstate(struct SKAnimationBoneFrame* frames, int boneCount, struct Transform* result) {
for (int i = 0; i < boneCount; ++i) {
result[i].position.x = (float)frames[i].position.x;
result[i].position.y = (float)frames[i].position.y;
result[i].position.z = (float)frames[i].position.z;
void skAnimatorExtractBone(struct SKAnimationBoneFrame* bone, struct Transform* result) {
result->position.x = (float)bone->position.x;
result->position.y = (float)bone->position.y;
result->position.z = (float)bone->position.z;
result[i].rotation.x = frames[i].rotation.x * (1.0f / 32767.0f);
result[i].rotation.y = frames[i].rotation.y * (1.0f / 32767.0f);
result[i].rotation.z = frames[i].rotation.z * (1.0f / 32767.0f);
float wSqrd = 1.0f - (result[i].rotation.x * result[i].rotation.x + result[i].rotation.y * result[i].rotation.y + result[i].rotation.z * result[i].rotation.z);
result->rotation.x = bone->rotation.x * (1.0f / 32767.0f);
result->rotation.y = bone->rotation.y * (1.0f / 32767.0f);
result->rotation.z = bone->rotation.z * (1.0f / 32767.0f);
float wSqrd = 1.0f - (result->rotation.x * result->rotation.x + result->rotation.y * result->rotation.y + result->rotation.z * result->rotation.z);
if (wSqrd <= 0.0f) {
result[i].rotation.w = 0.0f;
result->rotation.w = 0.0f;
} else {
result[i].rotation.w = sqrtf(wSqrd);
}
result[i].scale = gOneVec;
result->rotation.w = sqrtf(wSqrd);
}
}
void skAnimatorV2ReadTransform(struct SKAnimatorV2* animator, struct Transform* transforms) {
void skAnimatorInitZeroTransform(struct SKAnimator* animator, struct Transform* transforms) {
if (animator->latestBoneState == -1) {
return;
}
if (animator->blendLerp >= 1.0f) {
skAnimatorV2Extractstate(animator->boneState[animator->latestBoneState], animator->nBones, transforms);
return;
}
struct Transform fromState[animator->nBones];
struct Transform toState[animator->nBones];
skAnimatorV2Extractstate(animator->boneState[animator->latestBoneState], animator->nBones, toState);
skAnimatorV2Extractstate(animator->boneState[animator->latestBoneState ^ 1], animator->nBones, fromState);
for (int i = 0; i < animator->nBones; ++i) {
transformLerp(&fromState[i], &toState[i], animator->blendLerp, &transforms[i]);
transforms[i].position = gZeroVec;
transforms[i].rotation = gQuaternionZero;
transforms[i].scale = gOneVec;
}
}
void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transforms, float deltaTime) {
void skAnimatorNormalize(struct SKAnimator* animator, struct Transform* transforms) {
for (int i = 0; i < animator->nBones; ++i) {
quatNormalize(&transforms[i].rotation, &transforms[i].rotation);
}
}
void skAnimatorBlendTransform(struct SKAnimationBoneFrame* frame, struct Transform* transforms, int nBones, float weight) {
for (int i = 0; i < nBones; ++i) {
struct Transform boneTransform;
skAnimatorExtractBone(&frame[i], &boneTransform);
vector3AddScaled(&transforms[i].position, &boneTransform.position, weight, &transforms[i].position);
transforms[i].rotation.x += boneTransform.rotation.x * weight;
transforms[i].rotation.y += boneTransform.rotation.y * weight;
transforms[i].rotation.z += boneTransform.rotation.z * weight;
transforms[i].rotation.w += boneTransform.rotation.w * weight;
}
}
void skAnimatorReadTransformWithWeight(struct SKAnimator* animator, struct Transform* transforms, float weight) {
if (animator->blendLerp >= 1.0f) {
skAnimatorBlendTransform(animator->boneState[animator->latestBoneState], transforms, animator->nBones, weight);
return;
}
skAnimatorBlendTransform(animator->boneState[animator->latestBoneState], transforms, animator->nBones, animator->blendLerp * weight);
skAnimatorBlendTransform(animator->boneState[animator->latestBoneState ^ 1], transforms, animator->nBones, (1.0f - animator->blendLerp) * weight);
}
void skAnimatorReadTransform(struct SKAnimator* animator, struct Transform* transforms) {
if (animator->latestBoneState == -1) {
return;
}
skAnimatorInitZeroTransform(animator, transforms);
skAnimatorReadTransformWithWeight(animator, transforms, 1.0f);
skAnimatorNormalize(animator, transforms);
}
void skAnimatorStep(struct SKAnimator* animator, float deltaTime) {
struct SKAnimationClip* currentClip = animator->currentClip;
if (!currentClip) {
return;
}
skAnimatorV2ReadTransform(animator, transforms);
animator->currentTime += deltaTime;
float currentFrameFractional = animator->currentTime * currentClip->fps;
int currentFrame = (int)ceilf(currentFrameFractional);
while (currentFrame >= currentClip->nFrames) {
if (!(animator->flags & SKAnimatorV2FlagsLoop)) {
if (!(animator->flags & SKAnimatorFlagsLoop)) {
animator->blendLerp = 1.0f;
return;
}
@ -162,10 +187,22 @@ void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transfo
animator->blendLerp = 1.0f;
}
skAnimatorV2RequestNext(animator);
skAnimatorRequestNext(animator);
}
void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* clip, float startTime, int flags) {
void skAnimatorUpdate(struct SKAnimator* animator, struct Transform* transforms, float deltaTime) {
struct SKAnimationClip* currentClip = animator->currentClip;
if (!currentClip) {
return;
}
skAnimatorReadTransform(animator, transforms);
skAnimatorStep(animator, deltaTime);
}
void skAnimatorRunClip(struct SKAnimator* animator, struct SKAnimationClip* clip, float startTime, int flags) {
animator->currentClip = clip;
if (!clip) {
@ -184,7 +221,7 @@ void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip*
animator->currentTime = startTime;
animator->flags = flags;
skAnimatorV2RequestNext(animator);
skAnimatorRequestNext(animator);
}
static unsigned gSegmentLocations[SK_SEGMENT_COUNT];
@ -197,3 +234,47 @@ u32 skTranslateSegment(unsigned address) {
unsigned segment = (address >> 24) & 0xF;
return (address & 0xFFFFFF) + gSegmentLocations[segment];
}
void skBlenderInit(struct SKAnimatorBlender* blender, int nBones) {
skAnimatorInit(&blender->from, nBones);
skAnimatorInit(&blender->to, nBones);
blender->blendLerp = 0.0f;
}
void skBlenderApply(struct SKAnimatorBlender* blender, struct Transform* transforms) {
float lerp = blender->blendLerp;
if (blender->from.latestBoneState == -1) {
if (blender->to.latestBoneState == -1) {
return;
}
lerp = 1.0f;
}
if (blender->to.latestBoneState == -1) {
lerp = 0.0f;
}
skAnimatorInitZeroTransform(&blender->from, transforms);
if (lerp == 1.0f) {
skAnimatorReadTransformWithWeight(&blender->to, transforms, 1.0f);
} else if (lerp == 0.0f) {
skAnimatorReadTransformWithWeight(&blender->from, transforms, 1.0f);
} else {
skAnimatorReadTransformWithWeight(&blender->to, transforms, lerp);
skAnimatorReadTransformWithWeight(&blender->from, transforms, 1.0f - lerp);
}
}
void skBlenderCleanup(struct SKAnimatorBlender* blender) {
skAnimatorCleanup(&blender->from);
skAnimatorCleanup(&blender->to);
}
void skBlenderUpdate(struct SKAnimatorBlender* blender, struct Transform* transforms, float deltaTime) {
skBlenderApply(blender, transforms);
skAnimatorStep(&blender->from, deltaTime);
skAnimatorStep(&blender->to, deltaTime);
}

View file

@ -4,11 +4,11 @@
#include "skelatool_clip.h"
#include "../math/transform.h"
enum SKAnimatorV2Flags {
SKAnimatorV2FlagsLoop = (1 << 0),
enum SKAnimatorFlags {
SKAnimatorFlagsLoop = (1 << 0),
};
struct SKAnimatorV2 {
struct SKAnimator {
struct SKAnimationClip* currentClip;
float currentTime;
float blendLerp;
@ -19,15 +19,26 @@ struct SKAnimatorV2 {
short nBones;
};
void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones);
void skAnimatorV2Cleanup(struct SKAnimatorV2* animator);
void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transforms, float deltaTime);
void skAnimatorInit(struct SKAnimator* animator, int nBones);
void skAnimatorCleanup(struct SKAnimator* animator);
void skAnimatorUpdate(struct SKAnimator* animator, struct Transform* transforms, float deltaTime);
void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* clip, float startTime, int flags);
void skAnimatorRunClip(struct SKAnimator* animator, struct SKAnimationClip* clip, float startTime, int flags);
#define SK_SEGMENT_COUNT 16
void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocatoin);
u32 skTranslateSegment(unsigned address);
struct SKAnimatorBlender {
struct SKAnimator from;
struct SKAnimator to;
float blendLerp;
};
void skBlenderInit(struct SKAnimatorBlender* blender, int nBones);
void skBlenderCleanup(struct SKAnimatorBlender* animator);
void skBlenderUpdate(struct SKAnimatorBlender* blender, struct Transform* transforms, float deltaTime);
#endif