Files
SGVRETemplateDemo/Plugins/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/HandSocketComponent.cpp
T

1042 lines
30 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "Grippables/HandSocketComponent.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(HandSocketComponent)
#include "CoreMinimal.h"
#include "UObject/UObjectIterator.h"
#include "Engine/CollisionProfile.h"
#include "BoneContainer.h"
#include "Animation/AnimSequence.h"
#include "Animation/AnimInstanceProxy.h"
#include "Animation/PoseSnapshot.h"
#include "Animation/AnimData/AnimDataModel.h"
#include "Engine/SkinnedAssetCommon.h"
#include "Engine/SkinnedAsset.h"
//#include "VRExpansionFunctionLibrary.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/PoseableMeshComponent.h"
#include "GripMotionControllerComponent.h"
//#include "VRGripInterface.h"
//#include "VRBPDatatypes.h"
#include "Engine/SkinnedAssetCommon.h"
#include "Net/UnrealNetwork.h"
#include "Serialization/CustomVersion.h"
#if WITH_PUSH_MODEL
#include "Net/Core/PushModel/PushModel.h"
#endif
DEFINE_LOG_CATEGORY(LogVRHandSocketComponent);
const FGuid FVRHandSocketCustomVersion::GUID(0x5A018B7F, 0x48A7AFDE, 0xAFBEB580, 0xAD575412);
// Register the custom version with core
FCustomVersionRegistration GRegisterHandSocketCustomVersion(FVRHandSocketCustomVersion::GUID, FVRHandSocketCustomVersion::LatestVersion, TEXT("HandSocketVer"));
void UHandSocketComponent::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
Ar.UsingCustomVersion(FVRHandSocketCustomVersion::GUID);
#if WITH_EDITORONLY_DATA
const int32 CustomHandSocketVersion = Ar.CustomVer(FVRHandSocketCustomVersion::GUID);
if (CustomHandSocketVersion < FVRHandSocketCustomVersion::HandSocketStoringSetState)
{
bDecoupled = bDecoupleMeshPlacement;
}
#endif
}
//=============================================================================
UHandSocketComponent::UHandSocketComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bReplicateMovement = false;
PrimaryComponentTick.bCanEverTick = false;
PrimaryComponentTick.bStartWithTickEnabled = false;
// Setting absolute scale so we don't have to care about our parents scale
this->SetUsingAbsoluteScale(true);
//this->bReplicates = true;
bRepGameplayTags = true;
#if WITH_EDITORONLY_DATA
bTickedPose = false;
bDecoupled = false;
bShowVisualizationMesh = true;
bMirrorVisualizationMesh = false;
bShowRangeVisualization = false;
bFilterBonesByPostfix = false;
FilterPostfix = FString(TEXT("_r"));
#endif
HandRelativePlacement = FTransform::Identity;
bAlwaysInRange = false;
bDisabled = false;
bLockInPlace = false;
bMatchRotation = false;
OverrideDistance = 0.0f;
SlotPrefix = FName("VRGripP");
bUseCustomPoseDeltas = false;
HandTargetAnimation = nullptr;
MirroredScale = FVector(1.f, 1.f, -1.f);
bOnlySnapMesh = false;
bOnlyUseHandPose = false;
bIgnoreAttachBone = false;
bFlipForLeftHand = false;
bLeftHandDominant = false;
bOnlyFlipRotation = false;
MirrorAxis = EVRAxis::X;
FlipAxis = EVRAxis::Y;
}
UAnimSequence* UHandSocketComponent::GetTargetAnimation()
{
return HandTargetAnimation;
}
void UHandSocketComponent::GetAllHandSocketComponents(TArray<UHandSocketComponent*>& OutHandSockets)
{
for (TObjectIterator<UHandSocketComponent> It; It; ++It)
{
UHandSocketComponent* HandSocket = *It;
if (IsValid(HandSocket) && !HandSocket->IsTemplate())
{
OutHandSockets.Add(HandSocket);
}
}
}
bool UHandSocketComponent::GetAllHandSocketComponentsInRange(FVector SearchFromWorldLocation, float SearchRange, TArray<UHandSocketComponent*>& OutHandSockets)
{
float SearchDistSq = FMath::Square(SearchRange);
UHandSocketComponent* HandSocket = nullptr;
FTransform HandSocketTrans;
for (TObjectIterator<UHandSocketComponent> It; It; ++It)
{
HandSocket = *It;
if (IsValid(HandSocket) && !HandSocket->IsTemplate())
{
HandSocketTrans = HandSocket->GetRelativeTransform() * HandSocket->GetOwner()->GetActorTransform();
if (FVector::DistSquared(HandSocketTrans.GetLocation(), SearchFromWorldLocation) <= SearchDistSq)
{
OutHandSockets.Add(HandSocket);
}
}
}
return OutHandSockets.Num() > 0;
}
UHandSocketComponent* UHandSocketComponent::GetClosestHandSocketComponentInRange(FVector SearchFromWorldLocation, float SearchRange)
{
float SearchDistSq = FMath::Square(SearchRange);
UHandSocketComponent* ClosestHandSocket = nullptr;
float LastDist = 0.0f;
float DistSq = 0.0f;
bool bFoundOne = false;
UHandSocketComponent* HandSocket = nullptr;
FTransform HandSocketTrans;
for (TObjectIterator<UHandSocketComponent> It; It; ++It)
{
HandSocket = *It;
if (IsValid(HandSocket) && !HandSocket->IsTemplate())
{
HandSocketTrans = HandSocket->GetRelativeTransform() * HandSocket->GetOwner()->GetActorTransform();
DistSq = FVector::DistSquared(HandSocketTrans.GetLocation(), SearchFromWorldLocation);
if (DistSq <= SearchDistSq && (!bFoundOne || DistSq < LastDist))
{
bFoundOne = true;
ClosestHandSocket = HandSocket;
LastDist = DistSq;
}
}
}
return ClosestHandSocket;
}
bool UHandSocketComponent::GetAnimationSequenceAsPoseSnapShot(UAnimSequence* InAnimationSequence, FPoseSnapshot& OutPoseSnapShot, USkeletalMeshComponent* TargetMesh, bool bSkipRootBone, bool bFlipHand)
{
if (InAnimationSequence)
{
OutPoseSnapShot.SkeletalMeshName = /*TargetMesh ? TargetMesh->SkeletalMesh->GetFName(): */InAnimationSequence->GetSkeleton()->GetFName();
OutPoseSnapShot.SnapshotName = InAnimationSequence->GetFName();
OutPoseSnapShot.BoneNames.Empty();
OutPoseSnapShot.LocalTransforms.Empty();
TArray<FName> AnimSeqNames;
if (USkeleton* AnimationSkele = InAnimationSequence->GetSkeleton())
{
// pre-size the array to avoid unnecessary reallocation
OutPoseSnapShot.BoneNames.AddUninitialized(AnimationSkele->GetReferenceSkeleton().GetNum());
for (int32 i = 0; i < AnimationSkele->GetReferenceSkeleton().GetNum(); i++)
{
OutPoseSnapShot.BoneNames[i] = AnimationSkele->GetReferenceSkeleton().GetBoneName(i);
if (bFlipHand)
{
FString bName = OutPoseSnapShot.BoneNames[i].ToString();
if (bName.Contains("_r"))
{
bName = bName.Replace(TEXT("_r"), TEXT("_l"));
}
else
{
bName = bName.Replace(TEXT("_l"), TEXT("_r"));
}
OutPoseSnapShot.BoneNames[i] = FName(bName);
}
}
}
else
{
return false;
}
const FReferenceSkeleton& RefSkeleton = (TargetMesh) ? TargetMesh->GetSkinnedAsset()->GetRefSkeleton() : InAnimationSequence->GetSkeleton()->GetReferenceSkeleton();
FTransform LocalTransform;
const TArray<FTrackToSkeletonMap>& TrackMap = InAnimationSequence->GetCompressedTrackToSkeletonMapTable();
int32 TrackIndex = INDEX_NONE;
OutPoseSnapShot.LocalTransforms.Reserve(OutPoseSnapShot.BoneNames.Num());
for (int32 BoneNameIndex = 0; BoneNameIndex < OutPoseSnapShot.BoneNames.Num(); ++BoneNameIndex)
{
const FName& BoneName = OutPoseSnapShot.BoneNames[BoneNameIndex];
TrackIndex = INDEX_NONE;
if (BoneNameIndex != INDEX_NONE && BoneNameIndex < TrackMap.Num() && TrackMap[BoneNameIndex].BoneTreeIndex == BoneNameIndex)
{
TrackIndex = BoneNameIndex;
}
else
{
// This shouldn't happen but I need a fallback
// Don't currently want to reconstruct the map inversely
for (int i = 0; i < TrackMap.Num(); ++i)
{
if (TrackMap[i].BoneTreeIndex == BoneNameIndex)
{
TrackIndex = i;
break;
}
}
}
if (TrackIndex != INDEX_NONE && (!bSkipRootBone || TrackIndex != 0))
{
double TrackLocation = 0.0f;
InAnimationSequence->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), TrackLocation, false);
}
else
{
// otherwise, get ref pose if exists
const int32 BoneIDX = RefSkeleton.FindBoneIndex(BoneName);
if (BoneIDX != INDEX_NONE)
{
LocalTransform = RefSkeleton.GetRefBonePose()[BoneIDX];
}
else
{
LocalTransform = FTransform::Identity;
}
}
if (bFlipHand && (!bSkipRootBone || TrackIndex != 0))
{
FMatrix M = LocalTransform.ToMatrixWithScale();
M.Mirror(EAxis::X, EAxis::X);
M.Mirror(EAxis::Y, EAxis::Y);
M.Mirror(EAxis::Z, EAxis::Z);
LocalTransform.SetFromMatrix(M);
}
OutPoseSnapShot.LocalTransforms.Add(LocalTransform);
}
OutPoseSnapShot.bIsValid = true;
return true;
}
return false;
}
bool UHandSocketComponent::GetBlendedPoseSnapShot(FPoseSnapshot& PoseSnapShot, USkeletalMeshComponent* TargetMesh, bool bSkipRootBone, bool bFlipHand)
{
if (HandTargetAnimation)// && bUseCustomPoseDeltas && CustomPoseDeltas.Num() > 0)
{
PoseSnapShot.SkeletalMeshName = HandTargetAnimation->GetSkeleton()->GetFName();
PoseSnapShot.SnapshotName = HandTargetAnimation->GetFName();
PoseSnapShot.BoneNames.Empty();
PoseSnapShot.LocalTransforms.Empty();
TArray<FName> OrigBoneNames;
if(USkeleton * AnimationSkele = HandTargetAnimation->GetSkeleton())
{
// pre-size the array to avoid unnecessary reallocation
PoseSnapShot.BoneNames.AddUninitialized(AnimationSkele->GetReferenceSkeleton().GetNum());
OrigBoneNames.AddUninitialized(AnimationSkele->GetReferenceSkeleton().GetNum());
for (int32 i = 0; i < AnimationSkele->GetReferenceSkeleton().GetNum(); i++)
{
PoseSnapShot.BoneNames[i] = AnimationSkele->GetReferenceSkeleton().GetBoneName(i);
OrigBoneNames[i] = PoseSnapShot.BoneNames[i];
if (bFlipHand)
{
FString bName = PoseSnapShot.BoneNames[i].ToString();
if (bName.Contains("_r"))
{
bName = bName.Replace(TEXT("_r"), TEXT("_l"));
}
else
{
bName = bName.Replace(TEXT("_l"), TEXT("_r"));
}
PoseSnapShot.BoneNames[i] = FName(bName);
}
}
}
else
{
return false;
}
const FReferenceSkeleton& RefSkeleton = (TargetMesh) ? TargetMesh->GetSkinnedAsset()->GetRefSkeleton() : HandTargetAnimation->GetSkeleton()->GetReferenceSkeleton();
FTransform LocalTransform;
const TArray<FTrackToSkeletonMap>& TrackMap = HandTargetAnimation->GetCompressedTrackToSkeletonMapTable();
int32 TrackIndex = INDEX_NONE;
for (int32 BoneNameIndex = 0; BoneNameIndex < PoseSnapShot.BoneNames.Num(); ++BoneNameIndex)
{
TrackIndex = INDEX_NONE;
if (BoneNameIndex < TrackMap.Num() && TrackMap[BoneNameIndex].BoneTreeIndex == BoneNameIndex)
{
TrackIndex = BoneNameIndex;
}
else
{
// This shouldn't happen but I need a fallback
// Don't currently want to reconstruct the map inversely
for (int i = 0; i < TrackMap.Num(); ++i)
{
if (TrackMap[i].BoneTreeIndex == BoneNameIndex)
{
TrackIndex = i;
break;
}
}
}
const FName& BoneName = PoseSnapShot.BoneNames[BoneNameIndex];
if (TrackIndex != INDEX_NONE && (!bSkipRootBone || TrackIndex != 0))
{
/// SENSEGLOVE PATCH - BEGIN
//double TrackLocation = 0.0f;
double TrackLocation = HandTargetAnimation->GetPlayLength() * HandAnimationProgress;
/// SENSEGLOVE PATCH - END
HandTargetAnimation->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), TrackLocation, false);
}
else
{
// otherwise, get ref pose if exists
const int32 BoneIDX = RefSkeleton.FindBoneIndex(BoneName);
if (BoneIDX != INDEX_NONE)
{
LocalTransform = RefSkeleton.GetRefBonePose()[BoneIDX];
}
else
{
LocalTransform = FTransform::Identity;
}
}
if (bUseCustomPoseDeltas)
{
FQuat DeltaQuat = FQuat::Identity;
if (FBPVRHandPoseBonePair* HandPair = CustomPoseDeltas.FindByKey(OrigBoneNames[BoneNameIndex]))
{
DeltaQuat = HandPair->DeltaPose;
}
LocalTransform.ConcatenateRotation(DeltaQuat);
LocalTransform.NormalizeRotation();
}
if (bFlipHand && (!bSkipRootBone || TrackIndex != 0))
{
FMatrix M = LocalTransform.ToMatrixWithScale();
M.Mirror(EAxis::X, EAxis::X);
M.Mirror(EAxis::Y, EAxis::Y);
M.Mirror(EAxis::Z, EAxis::Z);
LocalTransform.SetFromMatrix(M);
}
PoseSnapShot.LocalTransforms.Add(LocalTransform);
}
PoseSnapShot.bIsValid = true;
return true;
}
else if (bUseCustomPoseDeltas && CustomPoseDeltas.Num() && TargetMesh)
{
PoseSnapShot.SkeletalMeshName = TargetMesh->GetSkinnedAsset()->GetSkeleton()->GetFName();
PoseSnapShot.SnapshotName = FName(TEXT("RawDeltaPose"));
PoseSnapShot.BoneNames.Empty();
PoseSnapShot.LocalTransforms.Empty();
TargetMesh->GetBoneNames(PoseSnapShot.BoneNames);
//PoseSnapShot.LocalTransforms = TargetMesh->GetSkinnedAsset()->GetSkeleton()->GetRefLocalPoses();
PoseSnapShot.LocalTransforms = TargetMesh->GetSkinnedAsset()->GetRefSkeleton().GetRefBonePose();
FQuat DeltaQuat = FQuat::Identity;
FName TargetBoneName = NAME_None;
for (FBPVRHandPoseBonePair& HandPair : CustomPoseDeltas)
{
if (bFlipHand)
{
FString bName = HandPair.BoneName.ToString();
if (bName.Contains("_r"))
{
bName = bName.Replace(TEXT("_r"), TEXT("_l"));
}
else
{
bName = bName.Replace(TEXT("_l"), TEXT("_r"));
}
TargetBoneName = FName(bName);
}
else
{
TargetBoneName = HandPair.BoneName;
}
int32 BoneIdx = TargetMesh->GetBoneIndex(TargetBoneName);
if (BoneIdx != INDEX_NONE)
{
DeltaQuat = HandPair.DeltaPose;
if (bFlipHand)
{
FTransform DeltaTrans(DeltaQuat);
FMatrix M = DeltaTrans.ToMatrixWithScale();
M.Mirror(EAxis::X, EAxis::X);
M.Mirror(EAxis::Y, EAxis::Y);
M.Mirror(EAxis::Z, EAxis::Z);
DeltaTrans.SetFromMatrix(M);
DeltaQuat = DeltaTrans.GetRotation();
}
PoseSnapShot.LocalTransforms[BoneIdx].ConcatenateRotation(DeltaQuat);
PoseSnapShot.LocalTransforms[BoneIdx].NormalizeRotation();
}
}
PoseSnapShot.bIsValid = true;
return true;
}
return false;
}
FTransform UHandSocketComponent::GetHandRelativePlacement()
{
// Optionally mirror for left hand
if (bDecoupleMeshPlacement)
{
if (USceneComponent* ParentComp = GetAttachParent())
{
return HandRelativePlacement.GetRelativeTransform(this->GetRelativeTransform());
//FTransform curTrans = HandRelativePlacement * ParentComp->GetComponentTransform();
//return curTrans.GetRelativeTransform(this->GetComponentTransform());
}
}
return HandRelativePlacement;
}
FTransform UHandSocketComponent::GetHandSocketTransform(UGripMotionControllerComponent* QueryController, bool bIgnoreOnlySnapMesh)
{
// Optionally mirror for left hand
if (!bIgnoreOnlySnapMesh && bOnlySnapMesh)
{
if (!QueryController)
{
// No controller input
UE_LOG(LogVRMotionController, Warning, TEXT("HandSocketComponent::GetHandSocketTransform was missing required motion controller for bOnlySnapMesh! Check that you are passing a controller into GetClosestSocketInRange!"));
}
else
{
return QueryController->GetPivotTransform();
}
}
if (bFlipForLeftHand)
{
if (!QueryController)
{
// No controller input
UE_LOG(LogVRMotionController, Warning, TEXT("HandSocketComponent::GetHandSocketTransform was missing required motion controller for bFlipForLeftand! Check that you are passing a controller into GetClosestSocketInRange!"));
}
else
{
EControllerHand HandType;
QueryController->GetHandType(HandType);
bool bIsRightHand = HandType == EControllerHand::Right;
if (bLeftHandDominant == bIsRightHand)
{
FTransform ReturnTrans = this->GetRelativeTransform();
if (USceneComponent* AttParent = this->GetAttachParent())
{
ReturnTrans.Mirror(GetAsEAxis(MirrorAxis), GetAsEAxis(FlipAxis));
if (bOnlyFlipRotation)
{
ReturnTrans.SetTranslation(this->GetRelativeLocation());
}
if (this->GetAttachSocketName() != NAME_None)
{
ReturnTrans = ReturnTrans * AttParent->GetSocketTransform(GetAttachSocketName(), RTS_Component);
}
ReturnTrans = ReturnTrans * AttParent->GetComponentTransform();
}
return ReturnTrans;
}
}
}
if (bLockInPlace)
{
FTransform ReturnTrans = this->GetRelativeTransform();
if (USceneComponent* AttParent = this->GetAttachParent())
{
if (this->GetAttachSocketName() != NAME_None)
{
ReturnTrans = ReturnTrans * AttParent->GetSocketTransform(GetAttachSocketName(), RTS_Component);
}
ReturnTrans = ReturnTrans * AttParent->GetComponentTransform();
}
else
{
ReturnTrans = this->GetComponentTransform(); // Fallback
}
return ReturnTrans;
}
else
{
return this->GetComponentTransform();
}
}
FTransform UHandSocketComponent::GetMeshRelativeTransform(bool bIsRightHand, bool bUseParentScale, bool bUseMirrorScale)
{
// Optionally mirror for left hand
// Failsafe
if (!this->GetAttachParent())
return FTransform::Identity;
FTransform relTrans = this->GetRelativeTransform();
FTransform HandTrans = GetHandRelativePlacement();
FTransform ReturnTrans = FTransform::Identity;
// Fix the scale
if (!bUseParentScale && this->IsUsingAbsoluteScale() /*&& !bDecoupleMeshPlacement*/)
{
FVector ParentScale = this->GetAttachParent()->GetComponentScale();
// Take parent scale out of our relative transform early
relTrans.ScaleTranslation(ParentScale);
ReturnTrans = HandTrans * relTrans;
// We add in the inverse of the parent scale to adjust the hand mesh
ReturnTrans.ScaleTranslation((FVector(1.0f) / ParentScale));
ReturnTrans.SetScale3D(FVector(1.0f));
}
else
{
ReturnTrans = HandTrans * relTrans;
}
// If we should mirror the transform, do it now that it is in our parent relative space
if ((bFlipForLeftHand && (bLeftHandDominant == bIsRightHand)))
{
//FTransform relTrans = this->GetRelativeTransform();
MirrorHandTransform(ReturnTrans, relTrans);
if (bUseMirrorScale)
{
ReturnTrans.SetScale3D(ReturnTrans.GetScale3D() * MirroredScale.GetSignVector());
}
}
if (bIgnoreAttachBone && this->GetAttachSocketName() != NAME_None)
{
ReturnTrans = ReturnTrans * GetAttachParent()->GetSocketTransform(GetAttachSocketName(), RTS_Component);
}
return ReturnTrans;
}
#if WITH_EDITORONLY_DATA
FTransform UHandSocketComponent::GetBoneTransformAtTime(UAnimSequence* MyAnimSequence, /*float AnimTime,*/ int BoneIdx, FName BoneName, bool bUseRawDataOnly)
{
double tracklen = MyAnimSequence->GetPlayLength();
FTransform BoneTransform = FTransform::Identity;
IAnimationDataController& AnimController = MyAnimSequence->GetController();
if (const IAnimationDataModel* AnimModel = AnimController.GetModel())
{
const TArray<FTrackToSkeletonMap>& TrackMap = MyAnimSequence->GetCompressedTrackToSkeletonMapTable();
int32 TrackIndex = INDEX_NONE;
if (BoneIdx != INDEX_NONE && BoneIdx < TrackMap.Num() && TrackMap[BoneIdx].BoneTreeIndex == BoneIdx)
{
TrackIndex = BoneIdx;
}
else
{
// This shouldn't happen but I need a fallback
// Don't currently want to reconstruct the map inversely
for (int i = 0; i < TrackMap.Num(); ++i)
{
if (TrackMap[i].BoneTreeIndex == BoneIdx)
{
TrackIndex = i;
break;
}
}
}
if (TrackIndex != INDEX_NONE)
{
FSkeletonPoseBoneIndex BoneIndex(TrackMap[TrackIndex].BoneTreeIndex);
if (BoneIndex.IsValid())
{
MyAnimSequence->GetBoneTransform(BoneTransform, BoneIndex, /*AnimTime*/ tracklen, bUseRawDataOnly);
return BoneTransform;
}
}
else
{
return FTransform::Identity;
}
}
return FTransform::Identity;
}
#endif
void UHandSocketComponent::OnRegister()
{
UWorld* MyWorld = GetWorld();
if (!MyWorld)
return;
TEnumAsByte<EWorldType::Type> MyWorldType = MyWorld->WorldType;
#if WITH_EDITORONLY_DATA
AActor* MyOwner = GetOwner();
if (bShowVisualizationMesh && (MyOwner != nullptr) && !IsRunningCommandlet())
{
if (HandVisualizerComponent == nullptr && bShowVisualizationMesh && (MyWorldType == EWorldType::EditorPreview || MyWorldType == EWorldType::Editor))
{
HandVisualizerComponent = NewObject<UPoseableMeshComponent>(MyOwner, NAME_None, RF_Transactional | RF_TextExportTransient);
HandVisualizerComponent->SetupAttachment(this);
HandVisualizerComponent->SetIsVisualizationComponent(true);
HandVisualizerComponent->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
HandVisualizerComponent->CastShadow = false;
HandVisualizerComponent->CreationMethod = CreationMethod;
//HandVisualizerComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
HandVisualizerComponent->SetComponentTickEnabled(false);
HandVisualizerComponent->SetHiddenInGame(true);
HandVisualizerComponent->RegisterComponentWithWorld(GetWorld());
//HandVisualizerComponent->SetUsingAbsoluteScale(true);
}
else if (/*!bShowVisualizationMesh && */HandVisualizerComponent)
{
HandVisualizerComponent->SetVisibility(false);
HandVisualizerComponent->DestroyComponent();
HandVisualizerComponent = nullptr;
}
if (HandVisualizerComponent)
{
bTickedPose = false;
if (VisualizationMesh)
{
if (HandPreviewMaterial)
{
HandVisualizerComponent->SetMaterial(0, HandPreviewMaterial);
}
HandVisualizerComponent->SetSkinnedAssetAndUpdate(VisualizationMesh);
}
PositionVisualizationMesh();
PoseVisualizationToAnimation(true);
}
}
#endif // WITH_EDITORONLY_DATA
if (bLockInPlace && (MyWorldType != EWorldType::EditorPreview && MyWorldType != EWorldType::Editor))
{
// Store current starting relative transform
//LockedRelativeTransform = GetRelativeTransform();
// Kill off child updates
SetUsingAbsoluteLocation(true);
SetUsingAbsoluteRotation(true);
}
Super::OnRegister();
}
#if WITH_EDITORONLY_DATA
void UHandSocketComponent::PositionVisualizationMesh()
{
if (!HandVisualizerComponent)
{
return;
}
if (USceneComponent* ParentAttach = this->GetAttachParent())
{
FTransform relTrans = this->GetRelativeTransform();
if (bDecoupled != bDecoupleMeshPlacement)
{
if (bDecoupleMeshPlacement)
{
HandRelativePlacement = HandRelativePlacement * GetRelativeTransform();
}
else
{
HandRelativePlacement = HandRelativePlacement.GetRelativeTransform(GetRelativeTransform());
}
}
FTransform HandPlacement = GetHandRelativePlacement();
FTransform ReturnTrans = (HandPlacement * relTrans);
if (bMirrorVisualizationMesh)//(bFlipForLeftHand && !bIsRightHand))
{
MirrorHandTransform(ReturnTrans, relTrans);
}
if ((bLeftHandDominant && !bMirrorVisualizationMesh) || (!bLeftHandDominant && bMirrorVisualizationMesh))
{
ReturnTrans.SetScale3D(ReturnTrans.GetScale3D() * MirroredScale);
}
HandVisualizerComponent->SetRelativeTransform(ReturnTrans.GetRelativeTransform(relTrans)/*newRel*/);
}
}
void UHandSocketComponent::HideVisualizationMesh()
{
if (!bShowVisualizationMesh && HandVisualizerComponent)
{
HandVisualizerComponent->SetVisibility(false);
HandVisualizerComponent->DestroyComponent();
HandVisualizerComponent = nullptr;
}
}
#endif
#if WITH_EDITORONLY_DATA
void UHandSocketComponent::PoseVisualizationToAnimation(bool bForceRefresh)
{
if (!HandVisualizerComponent || !HandVisualizerComponent->GetSkinnedAsset())
return;
TArray<FTransform> LocalPoses;
if (!HandTargetAnimation)
{
// Store local poses for posing
LocalPoses = HandVisualizerComponent->GetSkinnedAsset()->GetRefSkeleton().GetRefBonePose();
}
// Check out of the skin cache, the poses don't update otherwise when enabled
int32 NumLODs = HandVisualizerComponent->GetNumLODs();
HandVisualizerComponent->SkinCacheUsage.Empty(NumLODs);
for (int nLODs = 0; nLODs <= NumLODs; ++nLODs)
{
HandVisualizerComponent->SkinCacheUsage.Add(ESkinCacheUsage::Disabled);
}
// Now Pose the bones
TArray<FName> BonesNames;
HandVisualizerComponent->GetBoneNames(BonesNames);
int32 Bones = HandVisualizerComponent->GetNumBones();
for (int32 i = 0; i < Bones; i++)
{
if (!HandTargetAnimation && !bUseCustomPoseDeltas)
{
if (HandVisualizerComponent->GetBoneSpaceTransforms().Num() > 0)
{
HandVisualizerComponent->ResetBoneTransformByName(BonesNames[i]);
}
continue;
}
FName ParentBone = HandVisualizerComponent->GetParentBone(BonesNames[i]);
FTransform ParentTrans = FTransform::Identity;
if (ParentBone != NAME_None)
{
ParentTrans = HandVisualizerComponent->GetBoneTransformByName(ParentBone, EBoneSpaces::ComponentSpace);
}
FQuat DeltaQuat = FQuat::Identity;
if (bUseCustomPoseDeltas)
{
for (FBPVRHandPoseBonePair BonePairC : CustomPoseDeltas)
{
if (BonePairC.BoneName == BonesNames[i])
{
DeltaQuat = BonePairC.DeltaPose;
DeltaQuat.Normalize();
break;
}
}
}
FTransform BoneTrans = FTransform::Identity;
if (HandTargetAnimation)
{
BoneTrans = GetBoneTransformAtTime(HandTargetAnimation, /*FLT_MAX,*/ i, BonesNames[i], false); // true;
}
else
{
BoneTrans = LocalPoses[i];
//BoneTrans = HandVisualizerComponent->GetSkinnedAsset()->GetRefSkeleton().GetRefBonePose()[i];
}
BoneTrans = BoneTrans * ParentTrans;// *HandVisualizerComponent->GetComponentTransform();
BoneTrans.NormalizeRotation();
//DeltaQuat *= HandVisualizerComponent->GetComponentTransform().GetRotation().Inverse();
BoneTrans.ConcatenateRotation(DeltaQuat);
BoneTrans.NormalizeRotation();
HandVisualizerComponent->SetBoneTransformByName(BonesNames[i], BoneTrans, EBoneSpaces::ComponentSpace);
}
if (HandVisualizerComponent && (!bTickedPose || bForceRefresh))
{
// Tick Pose first
if (HandVisualizerComponent->IsRegistered())
{
bTickedPose = true;
HandVisualizerComponent->TickPose(1.0f, false);
if (HandVisualizerComponent->LeaderPoseComponent.IsValid())
{
HandVisualizerComponent->UpdateFollowerComponent();
}
else
{
HandVisualizerComponent->RefreshBoneTransforms(&HandVisualizerComponent->PrimaryComponentTick);
}
}
}
}
void UHandSocketComponent::AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector)
{
UHandSocketComponent* This = CastChecked<UHandSocketComponent>(InThis);
Collector.AddReferencedObject(This->HandVisualizerComponent);
Super::AddReferencedObjects(InThis, Collector);
}
void UHandSocketComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
{
Super::OnComponentDestroyed(bDestroyingHierarchy);
if (HandVisualizerComponent)
{
HandVisualizerComponent->DestroyComponent();
}
}
#endif
void UHandSocketComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// For std properties
FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true };
DOREPLIFETIME_WITH_PARAMS_FAST(UHandSocketComponent, bRepGameplayTags, PushModelParams);
DOREPLIFETIME_WITH_PARAMS_FAST(UHandSocketComponent, bReplicateMovement, PushModelParams);
// For properties with special conditions
FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true };
DOREPLIFETIME_WITH_PARAMS_FAST(UHandSocketComponent, GameplayTags, PushModelParamsWithCondition);
}
void UHandSocketComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker)
{
Super::PreReplication(ChangedPropertyTracker);
// Don't replicate if set to not do it
DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(UHandSocketComponent, GameplayTags, bRepGameplayTags);
DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(USceneComponent, RelativeLocation, bReplicateMovement);
DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(USceneComponent, RelativeRotation, bReplicateMovement);
DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(USceneComponent, RelativeScale3D, bReplicateMovement);
}
//=============================================================================
UHandSocketComponent::~UHandSocketComponent()
{
}
#if WITH_EDITOR
void UHandSocketComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
FProperty* PropertyThatChanged = PropertyChangedEvent.Property;
if (PropertyThatChanged != nullptr)
{
#if WITH_EDITORONLY_DATA
if (PropertyThatChanged->GetFName() == GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandTargetAnimation) ||
PropertyThatChanged->GetFName() == GET_MEMBER_NAME_CHECKED(UHandSocketComponent, VisualizationMesh)
)
{
PositionVisualizationMesh();
PoseVisualizationToAnimation(true);
}
else if (PropertyThatChanged->GetFName() == GET_MEMBER_NAME_CHECKED(UHandSocketComponent, CustomPoseDeltas))
{
PoseVisualizationToAnimation(true);
}
else if (PropertyThatChanged->GetFName() == GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement))
{
PositionVisualizationMesh();
}
else if (PropertyThatChanged->GetFName() == GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bShowVisualizationMesh))
{
HideVisualizationMesh();
}
#endif
}
}
#endif
UHandSocketComponent* UHandSocketComponent::GetHandSocketComponentFromObject(UObject* ObjectToCheck, FName SocketName)
{
if (AActor* OwningActor = Cast<AActor>(ObjectToCheck))
{
if (USceneComponent* OwningRoot = Cast<USceneComponent>(OwningActor->GetRootComponent()))
{
TArray<USceneComponent*> AttachChildren = OwningRoot->GetAttachChildren();
for (USceneComponent* AttachChild : AttachChildren)
{
if (AttachChild && AttachChild->IsA<UHandSocketComponent>() && AttachChild->GetFName() == SocketName)
{
return Cast<UHandSocketComponent>(AttachChild);
}
}
}
}
else if (USceneComponent* OwningRoot = Cast<USceneComponent>(ObjectToCheck))
{
TArray<USceneComponent*> AttachChildren = OwningRoot->GetAttachChildren();
for (USceneComponent* AttachChild : AttachChildren)
{
if (AttachChild && AttachChild->IsA<UHandSocketComponent>() && AttachChild->GetFName() == SocketName)
{
return Cast<UHandSocketComponent>(AttachChild);
}
}
}
return nullptr;
}
/////////////////////////////////////////////////
//- Push networking getter / setter functions
/////////////////////////////////////////////////
void UHandSocketComponent::SetRepGameplayTags(bool bNewRepGameplayTags)
{
bRepGameplayTags = bNewRepGameplayTags;
#if WITH_PUSH_MODEL
MARK_PROPERTY_DIRTY_FROM_NAME(UHandSocketComponent, bRepGameplayTags, this);
#endif
}
void UHandSocketComponent::SetReplicateMovement(bool bNewReplicateMovement)
{
bReplicateMovement = bNewReplicateMovement;
#if WITH_PUSH_MODEL
MARK_PROPERTY_DIRTY_FROM_NAME(UHandSocketComponent, bReplicateMovement, this);
#endif
}
FGameplayTagContainer& UHandSocketComponent::GetGameplayTags()
{
#if WITH_PUSH_MODEL
if (bRepGameplayTags)
{
MARK_PROPERTY_DIRTY_FROM_NAME(UHandSocketComponent, GameplayTags, this);
}
#endif
return GameplayTags;
}
/////////////////////////////////////////////////
//- End Push networking getter / setter functions
/////////////////////////////////////////////////
void UHandSocketAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
OwningSocket = Cast<UHandSocketComponent>(GetOwningComponent()->GetAttachParent());
}