fix(anim): the clip now drives the body — two causes, both measured
The body stood in an A-pose while the log said the clip was playing. Two independent defects, found by querying the imported asset instead of guessing: 1. PlayAnimation needs the component in AnimationSingleNode with a live single-node instance. The body is hidden at construction and only unhidden by the camera toggle, so the first call could land before the component was ready, and the Wanted == PlayingAnimation guard then returned forever. UpdateBodyAnimation now sets the mode, calls SetAnimation + Play, and re-asserts while the instance is missing. 2. The arms-down offsets lived only in the clip keys. The exporter writes clip data relative to the rest pose, so they arrived as a ±20 degree swing around an A-posed bind - which is exactly what the pose probe measured. apply_base_pose now bakes them into the rest pose before any clip is authored, the same trick mpfb_character_export.py --pose idle uses. The table is applied with inverted signs: as written, the FBX axis mapping produced arms raised in a V. Shot 6 confirms it: the arms hang at the sides. Still open and recorded - the idle pose reads awkwardly (arms forward, hands splayed) and the walk clip has no shot in motion; both are marked in TODO.md and Screenshots/README.md. Instrumentation removed; the diagnostics that remain are behind gigline.SetupLogs.
This commit is contained in:
1 parent
d0f94dff4e
commit
a1f5989cbb
39 files changed
+115
-59
No files matched your search
@@ -727,6 +727,7 @@ void AGigLineCharacter::Tick(float DeltaSeconds)
|
||||
// Speed-driven animation state: correct whether the player walked, was pushed,
|
||||
// or fell, and independent of which input produced the movement.
|
||||
UpdateBodyAnimation();
|
||||
|
||||
}
|
||||
|
||||
void AGigLineCharacter::ToggleCamera()
|
||||
@@ -771,16 +772,34 @@ void AGigLineCharacter::UpdateBodyAnimation()
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Wanted == PlayingAnimation)
|
||||
|
||||
// PlayAnimation is only an intent: it needs the component in single-node mode and
|
||||
// a live single-node instance. The body is hidden at construction and only
|
||||
// unhidden by the camera toggle, so the first call could land on a component that
|
||||
// was not ready and never retried - the clip name logged, the pose left at bind.
|
||||
// Driving the mode and the instance explicitly, and re-asserting every frame while
|
||||
// the instance is missing, makes that failure self-correcting.
|
||||
if (GetMesh()->GetAnimationMode() != EAnimationMode::AnimationSingleNode)
|
||||
{
|
||||
return;
|
||||
GetMesh()->SetAnimationMode(EAnimationMode::AnimationSingleNode);
|
||||
}
|
||||
PlayingAnimation = Wanted;
|
||||
if (CVarGigLineSetupLogs.GetValueOnGameThread())
|
||||
if (Wanted != PlayingAnimation || GetMesh()->GetSingleNodeInstance() == nullptr)
|
||||
{
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine: playing body clip %s"), *Wanted->GetName());
|
||||
PlayingAnimation = Wanted;
|
||||
GetMesh()->SetAnimation(Wanted);
|
||||
GetMesh()->Play(true);
|
||||
if (CVarGigLineSetupLogs.GetValueOnGameThread())
|
||||
{
|
||||
static bool bLoggedAnimState = false;
|
||||
if (!bLoggedAnimState)
|
||||
{
|
||||
bLoggedAnimState = true;
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine: body clip %s, mode=%d, instance=%s"),
|
||||
*Wanted->GetName(), static_cast<int32>(GetMesh()->GetAnimationMode()),
|
||||
GetMesh()->GetSingleNodeInstance() ? TEXT("ok") : TEXT("nil"));
|
||||
}
|
||||
}
|
||||
}
|
||||
GetMesh()->PlayAnimation(Wanted, true);
|
||||
}
|
||||
|
||||
void AGigLineCharacter::ResetToStart()
|
||||
|
||||
Reference in new issue
Block a user