fix crash + posture replication

This commit is contained in:
2026-03-03 10:21:52 +01:00
parent 1c4dbfc402
commit 45ee0c6f7d
6 changed files with 57 additions and 28 deletions

View File

@@ -89,9 +89,12 @@ void FAnimNode_PS_AI_ConvAgent_FacialExpression::Evaluate_AnyThread(FPoseContext
// covering eyes, eyebrows, cheeks, nose, and mouth mood.
// The downstream Lip Sync node will override mouth-area curves
// during speech, while non-mouth emotion curves pass through.
for (const auto& Pair : CachedEmotionCurves)
if (Output.Curve.IsValid())
{
Output.Curve.Set(Pair.Key, Pair.Value);
for (const auto& Pair : CachedEmotionCurves)
{
Output.Curve.Set(Pair.Key, Pair.Value);
}
}
}

View File

@@ -89,11 +89,14 @@ void FAnimNode_PS_AI_ConvAgent_LipSync::Evaluate_AnyThread(FPoseContext& Output)
// Skip near-zero values so that the upstream Facial Expression node's
// emotion curves (eyes, brows, mouth mood) pass through during silence.
// During speech, active lip sync curves override emotion's mouth curves.
for (const auto& Pair : CachedCurves)
if (Output.Curve.IsValid())
{
if (FMath::Abs(Pair.Value) > 0.01f)
for (const auto& Pair : CachedCurves)
{
Output.Curve.Set(Pair.Key, Pair.Value);
if (FMath::Abs(Pair.Value) > 0.01f)
{
Output.Curve.Set(Pair.Key, Pair.Value);
}
}
}
}

View File

@@ -379,6 +379,11 @@ void FAnimNode_PS_AI_ConvAgent_Posture::Evaluate_AnyThread(FPoseContext& Output)
// Evaluate the upstream pose (pass-through)
BasePose.Evaluate(Output);
// Guard: in packaged+network builds the curve container may not be
// initialized yet (skeleton not fully loaded). All Output.Curve access
// must be gated on this flag to avoid null-pointer crashes.
const bool bCurveValid = Output.Curve.IsValid();
// ── Periodic diagnostic (runs for EVERY instance, before any early return) ─
#if !UE_BUILD_SHIPPING
if (++EvalDebugFrameCounter % 300 == 1) // ~every 5 seconds at 60fps
@@ -432,11 +437,14 @@ void FAnimNode_PS_AI_ConvAgent_Posture::Evaluate_AnyThread(FPoseContext& Output)
#if ELEVENLABS_EYE_DIAGNOSTIC == 1
// MODE 1: CTRL curves → tests CORRECT MetaHuman CTRL naming
// Real format: CTRL_expressions_eyeLook{Dir}{L/R} (NOT eyeLookUpLeft!)
static const FName ForceCTRL(TEXT("CTRL_expressions_eyeLookUpL"));
Output.Curve.Set(ForceCTRL, 1.0f);
// Zero ARKit to isolate
static const FName ZeroARKit(TEXT("eyeLookUpLeft"));
Output.Curve.Set(ZeroARKit, 0.0f);
if (bCurveValid)
{
static const FName ForceCTRL(TEXT("CTRL_expressions_eyeLookUpL"));
Output.Curve.Set(ForceCTRL, 1.0f);
// Zero ARKit to isolate
static const FName ZeroARKit(TEXT("eyeLookUpLeft"));
Output.Curve.Set(ZeroARKit, 0.0f);
}
// Reset eye bone to ref pose to isolate
if (LeftEyeBoneIndex.GetInt() != INDEX_NONE
&& LeftEyeBoneIndex.GetInt() < Output.Pose.GetNumBones())
@@ -451,11 +459,14 @@ void FAnimNode_PS_AI_ConvAgent_Posture::Evaluate_AnyThread(FPoseContext& Output)
#elif ELEVENLABS_EYE_DIAGNOSTIC == 2
// MODE 2: ARKit curves → tests if mh_arkit_mapping_pose drives eyes
static const FName ForceARKit(TEXT("eyeLookUpLeft"));
Output.Curve.Set(ForceARKit, 1.0f);
// Zero CTRL to isolate
static const FName ZeroCTRL(TEXT("CTRL_expressions_eyeLookUpLeft"));
Output.Curve.Set(ZeroCTRL, 0.0f);
if (bCurveValid)
{
static const FName ForceARKit(TEXT("eyeLookUpLeft"));
Output.Curve.Set(ForceARKit, 1.0f);
// Zero CTRL to isolate
static const FName ZeroCTRL(TEXT("CTRL_expressions_eyeLookUpLeft"));
Output.Curve.Set(ZeroCTRL, 0.0f);
}
// Reset eye bone to ref pose to isolate
if (LeftEyeBoneIndex.GetInt() != INDEX_NONE
&& LeftEyeBoneIndex.GetInt() < Output.Pose.GetNumBones())
@@ -479,10 +490,13 @@ void FAnimNode_PS_AI_ConvAgent_Posture::Evaluate_AnyThread(FPoseContext& Output)
(LookUp * LeftEyeRefPoseRotation).GetNormalized());
}
// Zero curves to isolate
static const FName ZeroARKit(TEXT("eyeLookUpLeft"));
static const FName ZeroCTRL(TEXT("CTRL_expressions_eyeLookUpLeft"));
Output.Curve.Set(ZeroARKit, 0.0f);
Output.Curve.Set(ZeroCTRL, 0.0f);
if (bCurveValid)
{
static const FName ZeroARKit(TEXT("eyeLookUpLeft"));
static const FName ZeroCTRL(TEXT("CTRL_expressions_eyeLookUpLeft"));
Output.Curve.Set(ZeroARKit, 0.0f);
Output.Curve.Set(ZeroCTRL, 0.0f);
}
if (++EyeDiagLogCounter % 300 == 1)
{
UE_LOG(LogPS_AI_ConvAgent_PostureAnimNode, Verbose,
@@ -537,6 +551,7 @@ void FAnimNode_PS_AI_ConvAgent_Posture::Evaluate_AnyThread(FPoseContext& Output)
}
// (b) Blend CTRL eye curves: read animation's value, lerp with posture
if (bCurveValid)
{
const auto& CTRLMap = GetARKitToCTRLEyeMap();
for (const auto& Pair : CachedEyeCurves)
@@ -551,15 +566,15 @@ void FAnimNode_PS_AI_ConvAgent_Posture::Evaluate_AnyThread(FPoseContext& Output)
Output.Curve.Set(*CTRLName, BlendedValue);
}
}
}
// (c) Zero ARKit eye curves to prevent mh_arkit_mapping_pose
// from overwriting our carefully blended CTRL values.
// mh_arkit converts ARKit→CTRL additively; zeroing means
// it adds nothing for eyes, preserving our blend.
for (const auto& Pair : CachedEyeCurves)
{
Output.Curve.Set(Pair.Key, 0.0f);
// (c) Zero ARKit eye curves to prevent mh_arkit_mapping_pose
// from overwriting our carefully blended CTRL values.
// mh_arkit converts ARKit→CTRL additively; zeroing means
// it adds nothing for eyes, preserving our blend.
for (const auto& Pair : CachedEyeCurves)
{
Output.Curve.Set(Pair.Key, 0.0f);
}
}
}

View File

@@ -337,7 +337,15 @@ void UPS_AI_ConvAgent_PostureComponent::TickComponent(
if (FMath::Abs(BodyDelta) > 0.1f)
{
const float BodyStep = FMath::FInterpTo(0.0f, BodyDelta, SafeDeltaTime, BodyInterpSpeed);
Owner->AddActorWorldRotation(FRotator(0.0f, BodyStep, 0.0f));
// Only modify actor rotation on the authority (server/standalone).
// On clients, the rotation arrives via replication — calling
// AddActorWorldRotation here would fight with replicated updates,
// causing visible stuttering as the network periodically snaps
// the rotation back to the server's value.
if (Owner->HasAuthority())
{
Owner->AddActorWorldRotation(FRotator(0.0f, BodyStep, 0.0f));
}
}
}

View File

@@ -0,0 +1,35 @@
@echo off
chcp 65001 >nul
title Build PS_AI_Agent
echo ============================================================
echo PS_AI_Agent - Compilation plugin ElevenLabs (UE 5.5)
echo ============================================================
echo.
echo ATTENTION : Ferme l'Unreal Editor avant de continuer !
echo (Les DLL seraient verrouillees et la compilation echouerait)
echo.
pause
echo.
echo Compilation en cours...
echo (Seuls les .cpp modifies sont recompiles, ~16s)
echo.
powershell.exe -Command "& 'C:\Program Files\Epic Games\UE_5.5\Engine\Build\BatchFiles\RunUAT.bat' BuildEditor -project='E:\ASTERION\GIT\PS_AI_Agent\Unreal\PS_AI_Agent\PS_AI_Agent.uproject' -notools -noP4 2>&1"
echo.
if %ERRORLEVEL% == 0 (
echo ============================================================
echo SUCCES - Compilation terminee sans erreur.
echo Tu peux relancer l'Unreal Editor.
echo ============================================================
) else (
echo ============================================================
echo ECHEC - Erreur de compilation (code %ERRORLEVEL%)
echo Consulte le log ci-dessus pour le detail.
echo ============================================================
)
echo.
pause

View File

@@ -0,0 +1,35 @@
@echo off
chcp 65001 >nul
title Build PS_AI_Agent
echo ============================================================
echo PS_AI_Agent - Compilation plugin ElevenLabs (UE 5.5)
echo ============================================================
echo.
echo ATTENTION : Ferme l'Unreal Editor avant de continuer !
echo (Les DLL seraient verrouillees et la compilation echouerait)
echo.
pause
echo.
echo Compilation en cours...
echo (Seuls les .cpp modifies sont recompiles, ~16s)
echo.
powershell.exe -Command "& 'C:\Program Files\Epic Games\UE_5.5\Engine\Build\BatchFiles\RunUAT.bat' BuildEditor -project='C:\ASTERION\GIT\PS_AI_Agent\Unreal\PS_AI_Agent\PS_AI_Agent.uproject' -notools -noP4 2>&1"
echo.
if %ERRORLEVEL% == 0 (
echo ============================================================
echo SUCCES - Compilation terminee sans erreur.
echo Tu peux relancer l'Unreal Editor.
echo ============================================================
) else (
echo ============================================================
echo ECHEC - Erreur de compilation (code %ERRORLEVEL%)
echo Consulte le log ci-dessus pour le detail.
echo ============================================================
)
echo.
pause