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 "mathf.h"
#include <math.h> #include <math.h>
struct Quaternion gQuaternionZero = {0.0f, 0.0f, 0.0f, 0.0f};
void quatIdent(struct Quaternion* q) { void quatIdent(struct Quaternion* q) {
q->x = 0.0f; q->x = 0.0f;
q->y = 0.0f; q->y = 0.0f;

View file

@ -9,6 +9,8 @@ struct Quaternion {
float x, y, z, w; float x, y, z, w;
}; };
extern struct Quaternion gQuaternionZero;
void quatIdent(struct Quaternion* q); void quatIdent(struct Quaternion* q);
void quatAxisAngle(struct Vector3* axis, float angle, struct Quaternion* out); void quatAxisAngle(struct Vector3* axis, float angle, struct Quaternion* out);
void quatAxisComplex(struct Vector3* axis, struct Vector2* complex, 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); collisionSceneAddDynamicObject(&player->collisionObject);
skArmatureInit(&player->armature, &player_chell_armature); 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->body.velocity = *velocity;
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING; player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
@ -294,11 +295,53 @@ void playerGetMoveBasis(struct Transform* transform, struct Vector3* forward, st
vector3Normalize(right, right); 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) { void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
struct Vector3 forward; struct Vector3 forward;
struct Vector3 right; 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); int doorwayMask = worldCheckDoorwaySides(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom);
playerGetMoveBasis(&player->lookTransform, &forward, &right); 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); player->body.currentRoom = worldCheckDoorwayCrossings(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom, doorwayMask);
dynamicSceneSetRoomFlags(player->dynamicId, ROOM_FLAG_FROM_INDEX(player->body.currentRoom)); 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 RigidBody body;
struct Transform lookTransform; struct Transform lookTransform;
struct SKArmature armature; struct SKArmature armature;
struct SKAnimatorV2 animator; struct SKAnimatorBlender animator;
short grabbingThroughPortal; short grabbingThroughPortal;
short dynamicId; short dynamicId;
struct CollisionObject* grabbing; struct CollisionObject* grabbing;

View file

@ -100,7 +100,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def
skArmatureInit(&dropper->armature, &props_box_dropper_armature); 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->flags = 0;
dropper->reloadTimer = DROOPER_RELOAD_TIME; dropper->reloadTimer = DROOPER_RELOAD_TIME;
@ -109,7 +109,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def
} }
void boxDropperUpdate(struct BoxDropper* dropper) { 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) { if (dropper->reloadTimer > 0.0f) {
dropper->reloadTimer -= FIXED_DELTA_TIME; dropper->reloadTimer -= FIXED_DELTA_TIME;
@ -143,7 +143,7 @@ void boxDropperUpdate(struct BoxDropper* dropper) {
boxDropperFakePos(dropper, &pendingCubePos); boxDropperFakePos(dropper, &pendingCubePos);
decorObjectInit(&dropper->activeCube, decorObjectDefinitionForId(DECOR_TYPE_CUBE), &pendingCubePos, dropper->roomIndex); 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 &= ~BoxDropperFlagsCubeRequested;
dropper->flags |= BoxDropperFlagsCubeIsActive; dropper->flags |= BoxDropperFlagsCubeIsActive;

View file

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

View file

@ -60,7 +60,7 @@ void pedestalInit(struct Pedestal* pedestal, struct PedestalDefinition* definiti
skArmatureInit(&pedestal->armature, &pedestal_armature); 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); 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) { 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) { if (pedestal->flags & PedestalFlagsIsPointing) {
struct Vector2 target; struct Vector2 target;
@ -99,7 +99,7 @@ void pedestalUpdate(struct Pedestal* pedestal) {
void pedestalHide(struct Pedestal* pedestal) { void pedestalHide(struct Pedestal* pedestal) {
pedestal->flags |= PedestalFlagsDown; 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) { void pedestalPointAt(struct Pedestal* pedestal, struct Vector3* target) {

View file

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

View file

@ -31,7 +31,7 @@ void skAnimatorCopy(u32 romAddress, void* target, u32 size) {
osEPiStartDma(gAnimationPiHandle, ioMesg, OS_READ); osEPiStartDma(gAnimationPiHandle, ioMesg, OS_READ);
} }
void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) { void skAnimatorInit(struct SKAnimator* animator, int nBones) {
animator->currentClip = NULL; animator->currentClip = NULL;
animator->currentTime = 0.0f; animator->currentTime = 0.0f;
animator->blendLerp = 0.0f; animator->blendLerp = 0.0f;
@ -43,7 +43,7 @@ void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) {
animator->nBones = nBones; animator->nBones = nBones;
} }
void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) { void skAnimatorCleanup(struct SKAnimator* animator) {
free(animator->boneState[0]); free(animator->boneState[0]);
free(animator->boneState[1]); free(animator->boneState[1]);
@ -51,7 +51,7 @@ void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) {
animator->boneState[1] = NULL; animator->boneState[1] = NULL;
} }
void skAnimatorV2RequestNext(struct SKAnimatorV2* animator) { void skAnimatorRequestNext(struct SKAnimator* animator) {
struct SKAnimationClip* currentClip = animator->currentClip; struct SKAnimationClip* currentClip = animator->currentClip;
if (!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); 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) { void skAnimatorExtractBone(struct SKAnimationBoneFrame* bone, struct Transform* result) {
for (int i = 0; i < boneCount; ++i) { result->position.x = (float)bone->position.x;
result[i].position.x = (float)frames[i].position.x; result->position.y = (float)bone->position.y;
result[i].position.y = (float)frames[i].position.y; result->position.z = (float)bone->position.z;
result[i].position.z = (float)frames[i].position.z;
result[i].rotation.x = frames[i].rotation.x * (1.0f / 32767.0f); result->rotation.x = bone->rotation.x * (1.0f / 32767.0f);
result[i].rotation.y = frames[i].rotation.y * (1.0f / 32767.0f); result->rotation.y = bone->rotation.y * (1.0f / 32767.0f);
result[i].rotation.z = frames[i].rotation.z * (1.0f / 32767.0f); result->rotation.z = bone->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); 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) { if (wSqrd <= 0.0f) {
result[i].rotation.w = 0.0f; result->rotation.w = 0.0f;
} else { } else {
result[i].rotation.w = sqrtf(wSqrd); result->rotation.w = sqrtf(wSqrd);
}
result[i].scale = gOneVec;
} }
} }
void skAnimatorV2ReadTransform(struct SKAnimatorV2* animator, struct Transform* transforms) { void skAnimatorInitZeroTransform(struct SKAnimator* animator, struct Transform* transforms) {
if (animator->latestBoneState == -1) { if (animator->latestBoneState == -1) {
return; 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) { 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; struct SKAnimationClip* currentClip = animator->currentClip;
if (!currentClip) { if (!currentClip) {
return; return;
} }
skAnimatorV2ReadTransform(animator, transforms);
animator->currentTime += deltaTime; animator->currentTime += deltaTime;
float currentFrameFractional = animator->currentTime * currentClip->fps; float currentFrameFractional = animator->currentTime * currentClip->fps;
int currentFrame = (int)ceilf(currentFrameFractional); int currentFrame = (int)ceilf(currentFrameFractional);
while (currentFrame >= currentClip->nFrames) { while (currentFrame >= currentClip->nFrames) {
if (!(animator->flags & SKAnimatorV2FlagsLoop)) { if (!(animator->flags & SKAnimatorFlagsLoop)) {
animator->blendLerp = 1.0f; animator->blendLerp = 1.0f;
return; return;
} }
@ -162,10 +187,22 @@ void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transfo
animator->blendLerp = 1.0f; 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; animator->currentClip = clip;
if (!clip) { if (!clip) {
@ -184,7 +221,7 @@ void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip*
animator->currentTime = startTime; animator->currentTime = startTime;
animator->flags = flags; animator->flags = flags;
skAnimatorV2RequestNext(animator); skAnimatorRequestNext(animator);
} }
static unsigned gSegmentLocations[SK_SEGMENT_COUNT]; static unsigned gSegmentLocations[SK_SEGMENT_COUNT];
@ -196,4 +233,48 @@ void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocation) {
u32 skTranslateSegment(unsigned address) { u32 skTranslateSegment(unsigned address) {
unsigned segment = (address >> 24) & 0xF; unsigned segment = (address >> 24) & 0xF;
return (address & 0xFFFFFF) + gSegmentLocations[segment]; 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 "skelatool_clip.h"
#include "../math/transform.h" #include "../math/transform.h"
enum SKAnimatorV2Flags { enum SKAnimatorFlags {
SKAnimatorV2FlagsLoop = (1 << 0), SKAnimatorFlagsLoop = (1 << 0),
}; };
struct SKAnimatorV2 { struct SKAnimator {
struct SKAnimationClip* currentClip; struct SKAnimationClip* currentClip;
float currentTime; float currentTime;
float blendLerp; float blendLerp;
@ -19,15 +19,26 @@ struct SKAnimatorV2 {
short nBones; short nBones;
}; };
void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones); void skAnimatorInit(struct SKAnimator* animator, int nBones);
void skAnimatorV2Cleanup(struct SKAnimatorV2* animator); void skAnimatorCleanup(struct SKAnimator* animator);
void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transforms, float deltaTime); 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 #define SK_SEGMENT_COUNT 16
void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocatoin); void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocatoin);
u32 skTranslateSegment(unsigned address); 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 #endif