// Copyright Epic Games, Inc. All Rights Reserved. #include "ARBlueprintLibrary.h" #include "Features/IModularFeature.h" #include "Features/IModularFeatures.h" #include "Engine/Engine.h" #include "ARPin.h" #include "ARGeoTrackingSupport.h" #include "IXRTrackingSystem.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(ARBlueprintLibrary) TWeakPtr UARBlueprintLibrary::RegisteredARSystem = nullptr; EARTrackingQuality UARBlueprintLibrary::GetTrackingQuality() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetTrackingQuality(); } else { return EARTrackingQuality::NotTracking; } } EARTrackingQualityReason UARBlueprintLibrary::GetTrackingQualityReason() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetTrackingQualityReason(); } else { return EARTrackingQualityReason::InsufficientFeatures; } } bool UARBlueprintLibrary::IsARSupported(void) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->IsARAvailable(); } return false; } void UARBlueprintLibrary::StartARSession(UARSessionConfig* SessionConfig) { if (SessionConfig == nullptr) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) static const TCHAR NoSession_Warning[] = TEXT("Attempting to start an AR session without a session config object"); GEngine->AddOnScreenDebugMessage(INDEX_NONE, 3600.0f, FColor(255,48,16), NoSession_Warning); #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) return; } static const TCHAR NotARApp_Warning[] = TEXT("Attempting to start an AR session but there is no AR plugin configured. To use AR, enable the proper AR plugin in the Plugin Settings."); auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->StartARSession(SessionConfig); } else { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) GEngine->AddOnScreenDebugMessage(INDEX_NONE, 3600.0f, FColor(255,48,16), NotARApp_Warning); #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) } } void UARBlueprintLibrary::PauseARSession() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->PauseARSession(); } } void UARBlueprintLibrary::StopARSession() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->StopARSession(); } } FARSessionStatus UARBlueprintLibrary::GetARSessionStatus() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetARSessionStatus(); } else { return FARSessionStatus(EARSessionStatus::NotStarted); } } UARSessionConfig* UARBlueprintLibrary::GetSessionConfig() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return &ARSystem.Pin()->AccessSessionConfig(); } else { return nullptr; } } bool UARBlueprintLibrary::ToggleARCapture(const bool bOnOff, const EARCaptureType CaptureType) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->ToggleARCapture(bOnOff, CaptureType); } return false; } void UARBlueprintLibrary::SetEnabledXRCamera(bool bOnOff) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->SetEnabledXRCamera(bOnOff); } } FIntPoint UARBlueprintLibrary::ResizeXRCamera(const FIntPoint & InSize) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->ResizeXRCamera(InSize); } return FIntPoint(0, 0); } void UARBlueprintLibrary::SetAlignmentTransform( const FTransform& InAlignmentTransform ) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->SetAlignmentTransform( InAlignmentTransform ); } } TArray UARBlueprintLibrary::LineTraceTrackedObjects( const FVector2D ScreenCoord, bool bTestFeaturePoints, bool bTestGroundPlane, bool bTestPlaneExtents, bool bTestPlaneBoundaryPolygon ) { TArray Result; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { EARLineTraceChannels ActiveTraceChannels = (bTestFeaturePoints ? EARLineTraceChannels::FeaturePoint : EARLineTraceChannels::None) | (bTestGroundPlane ? EARLineTraceChannels::GroundPlane : EARLineTraceChannels::None) | (bTestPlaneExtents ? EARLineTraceChannels::PlaneUsingExtent : EARLineTraceChannels::None ) | (bTestPlaneBoundaryPolygon ? EARLineTraceChannels::PlaneUsingBoundaryPolygon : EARLineTraceChannels::None); Result = ARSystem.Pin()->LineTraceTrackedObjects(ScreenCoord, ActiveTraceChannels); } return Result; } TArray UARBlueprintLibrary::LineTraceTrackedObjects3D(const FVector Start, const FVector End, bool bTestFeaturePoints, bool bTestGroundPlane, bool bTestPlaneExtents, bool bTestPlaneBoundaryPolygon) { TArray Result; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { EARLineTraceChannels ActiveTraceChannels = (bTestFeaturePoints ? EARLineTraceChannels::FeaturePoint : EARLineTraceChannels::None) | (bTestGroundPlane ? EARLineTraceChannels::GroundPlane : EARLineTraceChannels::None) | (bTestPlaneExtents ? EARLineTraceChannels::PlaneUsingExtent : EARLineTraceChannels::None) | (bTestPlaneBoundaryPolygon ? EARLineTraceChannels::PlaneUsingBoundaryPolygon : EARLineTraceChannels::None); Result = ARSystem.Pin()->LineTraceTrackedObjects(Start, End, ActiveTraceChannels); } return Result; } TArray UARBlueprintLibrary::GetAllGeometries() { TArray Geometries; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { Geometries = ARSystem.Pin()->GetAllTrackedGeometries(); } return Geometries; } TArray UARBlueprintLibrary::GetAllGeometriesByClass(TSubclassOf GeometryClass) { if (!GeometryClass) { return {}; } TArray Geometries; for (auto Geometry : GetAllGeometries()) { if (Geometry && Geometry->GetClass()->IsChildOf(GeometryClass)) { Geometries.Add(Geometry); } } return MoveTemp(Geometries); } TArray UARBlueprintLibrary::GetAllPins() { TArray Pins; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { Pins = ARSystem.Pin()->GetAllPins(); } return Pins; } bool UARBlueprintLibrary::IsSessionTypeSupported(EARSessionType SessionType) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->IsSessionTypeSupported(SessionType); } return false; } void UARBlueprintLibrary::DebugDrawTrackedGeometry( UARTrackedGeometry* TrackedGeometry, UObject* WorldContextObject, FLinearColor Color, float OutlineThickness, float PersistForSeconds ) { UWorld* MyWorld = WorldContextObject->GetWorld(); if (TrackedGeometry != nullptr && MyWorld != nullptr) { TrackedGeometry->DebugDraw(MyWorld, Color, OutlineThickness, PersistForSeconds); } } void UARBlueprintLibrary::DebugDrawPin( UARPin* ARPin, UObject* WorldContextObject, FLinearColor Color, float Scale, float PersistForSeconds ) { UWorld* MyWorld = WorldContextObject->GetWorld(); if (ARPin != nullptr && MyWorld != nullptr) { ARPin->DebugDraw(MyWorld, Color, Scale, PersistForSeconds); } } UARLightEstimate* UARBlueprintLibrary::GetCurrentLightEstimate() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetCurrentLightEstimate(); } return nullptr; } UARPin* UARBlueprintLibrary::PinComponent( USceneComponent* ComponentToPin, const FTransform& PinToWorldTransform, UARTrackedGeometry* TrackedGeometry, const FName DebugName ) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->PinComponent( ComponentToPin, PinToWorldTransform, TrackedGeometry, DebugName ); } return nullptr; } UARPin* UARBlueprintLibrary::PinComponentToTraceResult( USceneComponent* ComponentToPin, const FARTraceResult& TraceResult, const FName DebugName ) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->PinComponent( ComponentToPin, TraceResult, DebugName ); } return nullptr; } bool UARBlueprintLibrary::PinComponentToARPin(USceneComponent* ComponentToPin, UARPin* Pin) { auto ARSystem = GetARSystem(); if (!ARSystem.IsValid()) { return false; } return ARSystem.Pin()->PinComponent(ComponentToPin, Pin); } void UARBlueprintLibrary::UnpinComponent( USceneComponent* ComponentToUnpin ) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { auto PinnedARSystem = ARSystem.Pin(); TArray AllPins = PinnedARSystem->GetAllPins(); const int32 AllPinsCount = AllPins.Num(); for (int32 i=0; iGetPinnedComponent() == ComponentToUnpin) { PinnedARSystem->RemovePin( AllPins[i] ); return; } } } } void UARBlueprintLibrary::RemovePin( UARPin* PinToRemove ) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->RemovePin( PinToRemove ); } } bool UARBlueprintLibrary::IsARPinLocalStoreSupported() { bool bSuccess = false; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { bSuccess = ARSystem.Pin()->IsLocalPinSaveSupported(); } return bSuccess; } bool UARBlueprintLibrary::IsARPinLocalStoreReady() { bool bSuccess = false; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { bSuccess = ARSystem.Pin()->ArePinsReadyToLoad(); } return bSuccess; } TMap UARBlueprintLibrary::LoadARPinsFromLocalStore() { TMap LoadedPins; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->LoadARPins(LoadedPins); } return LoadedPins; } bool UARBlueprintLibrary::SaveARPinToLocalStore(FName InSaveName, UARPin* InPin) { bool bSuccess = false; auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { bSuccess = ARSystem.Pin()->SaveARPin(InSaveName, InPin); } return bSuccess; } void UARBlueprintLibrary::RemoveARPinFromLocalStore(FName InSaveName) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->RemoveSavedARPin(InSaveName); } } void UARBlueprintLibrary::RemoveAllARPinsFromLocalStore() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { ARSystem.Pin()->RemoveAllSavedARPins(); } } void UARBlueprintLibrary::RegisterAsARSystem(const TSharedRef& NewARSystem) { RegisteredARSystem = NewARSystem; } const TWeakPtr& UARBlueprintLibrary::GetARSystem() { return RegisteredARSystem; } float UARTraceResultLibrary::GetDistanceFromCamera( const FARTraceResult& TraceResult ) { return TraceResult.GetDistanceFromCamera(); } FTransform UARTraceResultLibrary::GetLocalToTrackingTransform( const FARTraceResult& TraceResult ) { return TraceResult.GetLocalToTrackingTransform(); } FTransform UARTraceResultLibrary::GetLocalToWorldTransform( const FARTraceResult& TraceResult ) { return TraceResult.GetLocalToWorldTransform(); } FTransform UARTraceResultLibrary::GetLocalTransform( const FARTraceResult& TraceResult ) { return TraceResult.GetLocalTransform(); } UARTrackedGeometry* UARTraceResultLibrary::GetTrackedGeometry( const FARTraceResult& TraceResult ) { return TraceResult.GetTrackedGeometry(); } EARLineTraceChannels UARTraceResultLibrary::GetTraceChannel( const FARTraceResult& TraceResult ) { return TraceResult.GetTraceChannel(); } bool UARBlueprintLibrary::AddManualEnvironmentCaptureProbe(FVector Location, FVector Extent) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->AddManualEnvironmentCaptureProbe(Location, Extent); } return false; } EARWorldMappingState UARBlueprintLibrary::GetWorldMappingStatus() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetWorldMappingStatus(); } return EARWorldMappingState::NotAvailable; } TSharedPtr UARBlueprintLibrary::SaveWorld() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->SaveWorld(); } return TSharedPtr(); } TSharedPtr UARBlueprintLibrary::GetCandidateObject(FVector Location, FVector Extent) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetCandidateObject(Location, Extent); } return TSharedPtr(); } TArray UARBlueprintLibrary::GetPointCloud() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetPointCloud(); } return TArray(); } TArray UARBlueprintLibrary::GetSupportedVideoFormats(EARSessionType SessionType) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetSupportedVideoFormats(SessionType); } return TArray(); } UARCandidateImage* UARBlueprintLibrary::AddRuntimeCandidateImage(UARSessionConfig* SessionConfig, UTexture2D* CandidateTexture, FString FriendlyName, float PhysicalWidth) { auto ARSystem = GetARSystem(); if (ensure(ARSystem.IsValid())) { return ARSystem.Pin()->AddRuntimeCandidateImage(SessionConfig, CandidateTexture, FriendlyName, PhysicalWidth); } else { return nullptr; } } bool UARBlueprintLibrary::IsSessionTrackingFeatureSupported(EARSessionType SessionType, EARSessionTrackingFeature SessionTrackingFeature) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->IsSessionTrackingFeatureSupported(SessionType, SessionTrackingFeature); } else { return false; } } TArray UARBlueprintLibrary::GetAllTracked2DPoses() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetTracked2DPose(); } else { return {}; } } bool UARBlueprintLibrary::IsSceneReconstructionSupported(EARSessionType SessionType, EARSceneReconstruction SceneReconstructionMethod) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->IsSceneReconstructionSupported(SessionType, SceneReconstructionMethod); } else { return false; } } bool UARBlueprintLibrary::GetObjectClassificationAtLocation(const FVector& InWorldLocation, EARObjectClassification& OutClassification, FVector& OutClassificationLocation, float MaxLocationDiff) { auto AllGeometries = GetAllGeometries(); for (auto Geometry : AllGeometries) { if (auto MeshGeometry = Cast(Geometry)) { if (MeshGeometry->GetObjectClassificationAtLocation(InWorldLocation, OutClassification, OutClassificationLocation, MaxLocationDiff)) { return true; } } } return false; } namespace UARBlueprintLibraryNamespace { struct FSquareMatrix3 { float M[3][3]; FSquareMatrix3() = default; FORCEINLINE void SetColumn(int32 Index, FVector Axis) { M[Index][0] = (float) Axis.X; M[Index][1] = (float) Axis.Y; M[Index][2] = (float) Axis.Z; }; FORCEINLINE FVector GetColumn(int32 Index) const { return FVector(M[Index][0], M[Index][1], M[Index][2]); }; FORCEINLINE FSquareMatrix3 operator*(float Scale) const { FSquareMatrix3 ResultMat; for (int32 X = 0; X < 3; X++) { for (int32 Y = 0; Y < 3; Y++) { ResultMat.M[X][Y] = M[X][Y] * Scale; } } return ResultMat; } }; FSquareMatrix3 Invert(const FSquareMatrix3& InMatrix) { FSquareMatrix3 inverse; bool invertible; auto& M = InMatrix.M; float c00 = M[1][1] * M[2][2] - M[1][2] * M[2][1]; float c10 = M[1][2] * M[2][0] - M[1][0] * M[2][2]; float c20 = M[1][0] * M[2][1] - M[1][1] * M[2][0]; float det = M[0][0] * c00 + M[0][1] * c10 + M[0][2] * c20; if (FMath::Abs(det) > 0.000001f) { float invDet = 1.0f / det; inverse.SetColumn(0, { c00 * invDet, (M[0][2] * M[2][1] - M[0][1] * M[2][2]) * invDet, (M[0][1] * M[1][2] - M[0][2] * M[1][1]) * invDet }); inverse.SetColumn(1, { c10 * invDet, (M[0][0] * M[2][2] - M[0][2] * M[2][0]) * invDet, (M[0][2] * M[1][0] - M[0][0] * M[1][2]) * invDet }); inverse.SetColumn(2, { c20 * invDet, (M[0][1] * M[2][0] - M[0][0] * M[2][1]) * invDet, (M[0][0] * M[1][1] - M[0][1] * M[1][0]) * invDet }); invertible = true; } else { inverse.SetColumn(0, { 1,0,0 }); inverse.SetColumn(1, { 0,1,0 }); inverse.SetColumn(2, { 0,0,1 }); invertible = false; } return inverse; } FVector operator* (const FSquareMatrix3& InMatrix, const FVector& InVector) { auto& M = InMatrix.M; return { M[0][0] * InVector.X + M[1][0] * InVector.Y + M[2][0] * InVector.Z, M[0][1] * InVector.X + M[1][1] * InVector.Y + M[2][1] * InVector.Z, M[0][2] * InVector.X + M[1][2] * InVector.Y + M[2][2] * InVector.Z }; } } void UARBlueprintLibrary::CalculateClosestIntersection(const TArray& StartPoints, const TArray& EndPoints, FVector& ClosestIntersection) { checkf(StartPoints.Num() == EndPoints.Num(), TEXT("The StartPoints and Endpoints arrays must have the same size.")); float SXX = 0.0f; float SYY = 0.0f; float SZZ = 0.0f; float SXY = 0.0f; float SXZ = 0.0f; float SYZ = 0.0f; float CX = 0.0f; float CY = 0.0f; float CZ = 0.0f; for (int PointIdx = 0; PointIdx < StartPoints.Num(); ++PointIdx) { FVector NormView = (EndPoints[PointIdx] - StartPoints[PointIdx]).GetSafeNormal(); float XX = ((float)NormView.X * (float)NormView.X) - 1.0f; float YY = ((float)NormView.Y * (float)NormView.Y) - 1.0f; float ZZ = ((float)NormView.Z * (float)NormView.Z) - 1.0f; float XY = ((float)NormView.X * (float)NormView.Y); float XZ = ((float)NormView.X * (float)NormView.Z); float YZ = ((float)NormView.Y * (float)NormView.Z); SXX += XX; SYY += YY; SZZ += ZZ; SXY += XY; SXZ += XZ; SYZ += YZ; CX += ((float)StartPoints[PointIdx].X * XX) + ((float)StartPoints[PointIdx].Y * XY) + ((float)StartPoints[PointIdx].Z * XZ); CY += ((float)StartPoints[PointIdx].X * XY) + ((float)StartPoints[PointIdx].Y * YY) + ((float)StartPoints[PointIdx].Z * YZ); CZ += ((float)StartPoints[PointIdx].X * XZ) + ((float)StartPoints[PointIdx].Y * YZ) + ((float)StartPoints[PointIdx].Z * ZZ); } UARBlueprintLibraryNamespace::FSquareMatrix3 S; S.SetColumn(0, { SXX, SXY, SXZ }); S.SetColumn(1, { SXY, SYY, SYZ }); S.SetColumn(2, { SXZ, SYZ, SZZ }); FVector C(CX, CY, CZ); ClosestIntersection = UARBlueprintLibraryNamespace::Invert(S) * C; } void UARBlueprintLibrary::CalculateAlignmentTransform(const FTransform& TransformInFirstCoordinateSystem, const FTransform& TransformInSecondCoordinateSystem, FTransform& AlignmentTransform) { AlignmentTransform = TransformInSecondCoordinateSystem * TransformInFirstCoordinateSystem.Inverse(); } void UARBlueprintLibrary::SetARWorldOriginLocationAndRotation(FVector OriginLocation, FRotator OriginRotation, bool bIsTransformInWorldSpace, bool bMaintainUpDirection) { // Zero out the pitch and roll if needed if (bMaintainUpDirection) { OriginRotation.Pitch = 0; OriginRotation.Roll = 0; } // For P in local space we have T (local) * T (Alignment) * T (tracking to world) = T (World) // The goal is to compute a new alignment transform so that T (local) * T (New Alignment) * T (tracking to world) = T (Identity) auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { if (auto TrackingSystem = ARSystem.Pin()->GetXRTrackingSystem()) { const auto TrackingToWorldTransform = TrackingSystem->GetTrackingToWorldTransform(); const auto TrackingToWorldTransformInverse = TrackingToWorldTransform.Inverse(); const auto AlignmentTransform = GetAlignmentTransform(); FTransform LocalTransform; if (bIsTransformInWorldSpace) { const FTransform WorldTransform(OriginRotation, OriginLocation); LocalTransform = WorldTransform * TrackingToWorldTransformInverse * AlignmentTransform.Inverse(); } else { // Note that the local transform has the inverse scale of the alignment transform // this makes sure the scale of the alignment transform is unchanged from the calculation below LocalTransform = FTransform(OriginRotation, OriginLocation, FVector::OneVector / AlignmentTransform.GetScale3D()); } // now we have the local transform, from T (local) * T (New Alignment) * T (tracking to world) = T (Identity), we have // T (New Alignment) = T (inverse local) * T (Identity) * T (inverse tracking to world) auto NewAlignmentTransform = LocalTransform.Inverse() * TrackingToWorldTransformInverse; if (bMaintainUpDirection) { auto Rotator = NewAlignmentTransform.Rotator(); Rotator.Pitch = 0; Rotator.Roll = 0; NewAlignmentTransform.SetRotation(Rotator.Quaternion()); } auto Rotator = NewAlignmentTransform.Rotator(); SetAlignmentTransform(NewAlignmentTransform); } } } void UARBlueprintLibrary::SetARWorldScale(float InWorldScale) { if (ensure(InWorldScale > 0.f)) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { if (auto TrackingSystem = ARSystem.Pin()->GetXRTrackingSystem()) { const auto AlignmentTransform = GetAlignmentTransform(); FTransform NewAlignmentTransform(AlignmentTransform.GetRotation(), AlignmentTransform.GetLocation(), FVector(1.f / InWorldScale)); SetAlignmentTransform(NewAlignmentTransform); const auto TrackingToWorldTransform = TrackingSystem->GetTrackingToWorldTransform(); const auto TrackingToWorldTransformInverse = TrackingToWorldTransform.Inverse(); // For P in local space whose world space transform is at the origin // We have T (local) * T (Alignment) * T (tracking to world) = T (Identity) // yields T (local) = T (inverse tracking to world) * T (inverse alignment) const auto LocalTransform = TrackingToWorldTransform.Inverse() * AlignmentTransform.Inverse(); // We want to make sure the new alignment transform still puts P at the origin after the world scale change // So we calculate where P is after the alignment transform change and move the world origin to it // const auto WorldTransform = InverseAlignmentTransform * NewAlignmentTransform; SetARWorldOriginLocationAndRotation(LocalTransform.GetLocation(), LocalTransform.Rotator(), false, false); } } } } float UARBlueprintLibrary::GetARWorldScale() { const auto AlignmentTransform = GetAlignmentTransform(); // Assuming the scale is uniform return 1.f / (float)AlignmentTransform.GetScale3D().X; } FTransform UARBlueprintLibrary::GetAlignmentTransform() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetAlignmentTransform(); } return FTransform::Identity; } bool UARBlueprintLibrary::AddTrackedPointWithName(const FTransform& WorldTransform, const FString& PointName, bool bDeletePointsWithSameName) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid() && PointName.Len()) { return ARSystem.Pin()->AddTrackedPointWithName(WorldTransform, PointName, bDeletePointsWithSameName); } return false; } TArray UARBlueprintLibrary::FindTrackedPointsByName(const FString& PointName) { TArray Points; for (auto Point : GetAllGeometriesByClass()) { if (Point && Point->GetName() == PointName) { Points.Add(Point); } } return MoveTemp(Points); } int32 UARBlueprintLibrary::GetNumberOfTrackedFacesSupported() { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetNumberOfTrackedFacesSupported(); } return 0; } UARTexture* UARBlueprintLibrary::GetARTexture(EARTextureType TextureType) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetARTexture(TextureType); } return nullptr; } bool UARBlueprintLibrary::GetCameraIntrinsics(FARCameraIntrinsics& OutCameraIntrinsics) { auto ARSystem = GetARSystem(); if (ARSystem.IsValid()) { return ARSystem.Pin()->GetCameraIntrinsics(OutCameraIntrinsics); } return false; }