// Georgy Treshchev 2025. #pragma once #include "CoreMinimal.h" #include "RealisticMetaHumanLipSyncGenerator.h" #include "Animation/AnimNodeBase.h" #include "BlendRealisticMetaHumanLipSyncAnimNode.generated.h" USTRUCT(BlueprintType) struct RUNTIMEMETAHUMANLIPSYNC_API FAnimNode_BlendRealisticMetaHumanLipSync : public FAnimNode_Base { GENERATED_BODY() public: FAnimNode_BlendRealisticMetaHumanLipSync(); // FAnimNode_Base interface virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override; virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override; virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override; virtual void Evaluate_AnyThread(FPoseContext& Output) override; virtual void GatherDebugData(FNodeDebugData& DebugData) override; // End of FAnimNode_Base interface UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links) FPoseLink SourcePose; UPROPERTY(EditAnywhere, BlueprintReadWrite, transient, Category=Copy, meta=(PinShownByDefault)) TWeakObjectPtr LipSyncGenerator; /** Controls how quickly facial expressions transition during active speech. Higher values result in faster, more abrupt transitions */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta=(ClampMin="0.1", ClampMax="100.0")) float InterpolationSpeed = 30.0f; /** Controls how quickly facial expressions transition back to idle/neutral state. Lower values create smoother, more gradual returns to rest pose */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta=(ClampMin="0.1", ClampMax="100.0")) float IdleInterpolationSpeed = 15.0f; /** Duration in seconds after which lip sync resets to idle state. Useful to prevent expressions from continuing after audio stops */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) float ResetTime = 0.2f; /** When enabled, preserves the last emotional state during idle periods instead of resetting to neutral */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) bool bPreserveIdleState = false; /** Controls which facial regions are preserved during idle state. Only effective when bPreserveIdleState is true */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta=(EditCondition="bPreserveIdleState")) bool bPreserveEyeExpressions = true; /** Controls which facial regions are preserved during idle state. Only effective when bPreserveIdleState is true */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta=(EditCondition="bPreserveIdleState")) bool bPreserveBrowExpressions = true; /** Controls which facial regions are preserved during idle state. Only effective when bPreserveIdleState is true */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta=(EditCondition="bPreserveIdleState")) bool bPreserveMouthShape = false; private: /** Current control values for smooth interpolation */ TMap CurrentControlValues; /** Target control values from the lip sync generator */ TMap TargetControlValues; /** Preserved idle state values */ TMap IdleStateValues; /** Time since the last control values change */ float TimeSinceLastChange = 0.0f; /** Helper function to determine if a control should be preserved during idle */ bool ShouldPreserveControl(const FString& ControlName) const; /** Helper function to update idle state preservation */ void UpdateIdleStatePreservation(); };