// Copyright (c) Meta Platforms, Inc. and affiliates. #pragma once #include "CoreMinimal.h" #include "Components/SkeletalMeshComponent.h" #include "OculusXRMorphTargetsController.h" #include "OculusXRMovementTypes.h" #include "OculusXRFaceTrackingComponent.generated.h" UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent, DisplayName = "OculusXR Face Tracking Component"), ClassGroup = OculusXRHMD) class OCULUSXRMOVEMENT_API UOculusXRFaceTrackingComponent : public UActorComponent { GENERATED_BODY() public: UOculusXRFaceTrackingComponent(); virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; /** * Set face expression value with expression key and value(0-1). * * @param Expression : The expression key that will be modified. * @param Value : The new value to assign to the expression, 0 will remove all changes. */ UFUNCTION(BlueprintCallable, Category = "Components|OculusXRFaceTracking", meta = (UnsafeDuringActorConstruction = "true")) void SetExpressionValue(EOculusXRFaceExpression Expression, float Value); /** * Get a face expression value given an expression key. * * @param Expression : The expression key that will be queried. */ UFUNCTION(BlueprintCallable, Category = "Components|OculusXRFaceTracking") float GetExpressionValue(EOculusXRFaceExpression Expression) const; /** * Clears all face expression values. */ UFUNCTION(BlueprintCallable, Category = "Components|OculusXRFaceTracking") void ClearExpressionValues(); /** * The name of the skinned mesh component that this component targets for facial expression. * This must be the name of a component on this actor. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") FName TargetMeshComponentName; /** * If the face data is invalid for at least this or longer than this time then all face blendshapes/morph targets are reset to zero. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") float InvalidFaceDataResetTime; /** * The list of expressions that this component supports. * Names are validated on startup so only valid morph targets on the skeletal mesh will be targeted. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") TMap ExpressionNames; /** * An array of optional expression modifiers that can be applied. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") TArray ExpressionModifiers; /** * This flag determines if the face should be updated or not during the components tick. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") bool bUpdateFace; /** * This flag determines if the face should be modified with Expression Modifiers or not during the components tick. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") bool bUseModifiers; private: bool InitializeFaceTracking(); // The mesh component targeted for expressions UPROPERTY() USkinnedMeshComponent* TargetMeshComponent; // Which mapped expressions are valid TStaticArray(EOculusXRFaceExpression::COUNT)> ExpressionValid; // Morph targets controller FOculusXRMorphTargetsController MorphTargets; FOculusXRFaceState FaceState; // Timer that counts up until we reset morph curves if we've failed to get face state float InvalidFaceStateTimer; // Stop the tracker just once. static int TrackingInstanceCount; };