// @lint-ignore-every LICENSELINT // Copyright Epic Games, Inc. All Rights Reserved. #include "OculusXRHandComponent.h" #include "OculusXRInput.h" #include "Engine/SkeletalMesh.h" #include "Components/InputComponent.h" #include "Materials/MaterialInterface.h" #include "GameFramework/Pawn.h" #include "GameFramework/PlayerController.h" UOculusXRHandComponent::UOculusXRHandComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { PrimaryComponentTick.bCanEverTick = true; PrimaryComponentTick.bStartWithTickEnabled = true; PrimaryComponentTick.TickGroup = TG_PrePhysics; bHasAuthority = false; bAutoActivate = true; bWantsInitializeComponent = true; for (uint8 BoneIndex = 0; BoneIndex < (uint8)EOculusXRBone::Bone_Max; BoneIndex++) { BoneNameMappings.Add((EOculusXRBone)BoneIndex, TEXT("")); } } void UOculusXRHandComponent::BeginPlay() { Super::BeginPlay(); // Use custom mesh if a skeletal mesh is already set, else try to load the runtime mesh if (GetSkinnedAsset()) { bCustomHandMesh = true; bSkeletalMeshInitialized = true; } else { RuntimeSkeletalMesh = NewObject(this, TEXT("OculusHandMesh")); InitializeSkeletalMesh(); } } void UOculusXRHandComponent::InitializeSkeletalMesh() { if (RuntimeSkeletalMesh) { if (UOculusXRInputFunctionLibrary::GetHandSkeletalMesh(RuntimeSkeletalMesh, SkeletonType, MeshType)) { SetSkinnedAssetAndUpdate(RuntimeSkeletalMesh, true); if (MaterialOverride) { SetMaterial(0, MaterialOverride); } CachedBaseMaterial = GetMaterial(0); bSkeletalMeshInitialized = true; // Initialize physics capsules on the runtime mesh if (bInitializePhysics) { CollisionCapsules = UOculusXRInputFunctionLibrary::InitializeHandPhysics(SkeletonType, this); } } } } void UOculusXRHandComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); #if WITH_EDITOR if (!bSkeletalMeshInitialized && !bCustomHandMesh) { InitializeSkeletalMesh(); } #endif if (IsInGameThread()) { // Cache state from the game thread for use on the render thread const AActor* MyOwner = GetOwner(); bHasAuthority = MyOwner->HasLocalNetOwner(); int i = 0; } if (bHasAuthority) { bool bHidden = false; if (UOculusXRInputFunctionLibrary::IsHandTrackingEnabled()) { // Update Visibility based on Confidence if (ConfidenceBehavior == EOculusXRConfidenceBehavior::HideActor) { EOculusXRTrackingConfidence TrackingConfidence = UOculusXRInputFunctionLibrary::GetTrackingConfidence(SkeletonType); bHidden |= TrackingConfidence != EOculusXRTrackingConfidence::High; } // Update Hand Scale if (bUpdateHandScale) { float NewScale = UOculusXRInputFunctionLibrary::GetHandScale(SkeletonType); SetRelativeScale3D(FVector(NewScale)); } // Update Bone Pose Rotations if (GetSkinnedAsset()) { UpdateBonePose(); } #if OCULUS_INPUT_SUPPORTED_PLATFORMS // Check for system gesture pressed through player controller if (APawn* Pawn = Cast(GetOwner())) { if (APlayerController* PC = Pawn->GetController()) { if (PC->WasInputKeyJustPressed(SkeletonType == EOculusXRHandType::HandLeft ? OculusXRInput::FOculusKey::OculusHand_Left_SystemGesture : OculusXRInput::FOculusKey::OculusHand_Right_SystemGesture)) { SystemGesturePressed(); } if (PC->WasInputKeyJustReleased(SkeletonType == EOculusXRHandType::HandLeft ? OculusXRInput::FOculusKey::OculusHand_Left_SystemGesture : OculusXRInput::FOculusKey::OculusHand_Right_SystemGesture)) { SystemGestureReleased(); } } } #endif } else { bHidden = true; } if (bHidden != bHiddenInGame) { SetHiddenInGame(bHidden); for (int32 i = 0; i < CollisionCapsules.Num(); i++) { CollisionCapsules[i].Capsule->SetCollisionEnabled(bHidden ? ECollisionEnabled::NoCollision : ECollisionEnabled::QueryAndPhysics); } } } } void UOculusXRHandComponent::UpdateBonePose() { if (bCustomHandMesh) { for (auto& BoneElem : BoneNameMappings) { // Set Root Bone Rotaiton if (BoneElem.Key == EOculusXRBone::Wrist_Root) { FQuat RootBoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, EOculusXRBone::Wrist_Root); RootBoneRotation *= HandRootFixupRotation; RootBoneRotation.Normalize(); BoneSpaceTransforms[0].SetRotation(RootBoneRotation); } else { // Set Remaing Bone Rotations int32 BoneIndex = GetSkinnedAsset()->GetRefSkeleton().FindBoneIndex(BoneElem.Value); if (BoneIndex >= 0) { FQuat BoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, (EOculusXRBone)BoneElem.Key); BoneSpaceTransforms[BoneIndex].SetRotation(BoneRotation); } } } } else { // Set Root Bone Rotation FQuat RootBoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, EOculusXRBone::Wrist_Root); RootBoneRotation *= HandRootFixupRotation; RootBoneRotation.Normalize(); BoneSpaceTransforms[0].SetRotation(RootBoneRotation); // Set Remaining Bone Rotations for (uint32 BoneIndex = 1; BoneIndex < (uint32)GetSkinnedAsset()->GetRefSkeleton().GetNum(); BoneIndex++) { FQuat BoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, (EOculusXRBone)BoneIndex); BoneSpaceTransforms[BoneIndex].SetRotation(BoneRotation); } } MarkRefreshTransformDirty(); } void UOculusXRHandComponent::SystemGesturePressed() { if (SystemGestureBehavior == EOculusXRSystemGestureBehavior::SwapMaterial) { if (SystemGestureMaterial) { SetMaterial(0, SystemGestureMaterial); } else { UE_LOG(LogTemp, Log, TEXT("System Gesture Behavior was set to Swap Material but no System Gesture Material was provided!")); } } } void UOculusXRHandComponent::SystemGestureReleased() { if (SystemGestureBehavior == EOculusXRSystemGestureBehavior::SwapMaterial) { if (CachedBaseMaterial) { SetMaterial(0, CachedBaseMaterial); } else { UE_LOG(LogTemp, Log, TEXT("System Gesture Behavior was set to Swap Material but no System Gesture Material was provided!")); } } }