Android build settings + metaxr
This commit is contained in:
412
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKit.h
Normal file
412
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKit.h
Normal file
@@ -0,0 +1,412 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
|
||||
#include "MRUtilityKit.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogMRUK, Log, All);
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKInitStatus : uint8
|
||||
{
|
||||
/// Not Initialized.
|
||||
None,
|
||||
/// Is busy Initializing.
|
||||
Busy,
|
||||
/// Has finished Initializing.
|
||||
Complete,
|
||||
/// Failed to initialize.
|
||||
Failed,
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKCoordModeU : uint8
|
||||
{
|
||||
/// The texture coordinates start at 0 and increase by 1 unit every meter.
|
||||
Metric,
|
||||
/// The texture coordinates start at 0 and increase by 1 unit every meter but are adjusted to end on a whole number to avoid seams.
|
||||
MetricSeamless,
|
||||
/// The texture coordinates are adjusted to the other dimensions to ensure the aspect ratio is maintained.
|
||||
MaintainAspectRatio,
|
||||
/// The texture coordinates are adjusted to the other dimensions to ensure the aspect ratio is maintained but are adjusted to end on a whole number to avoid seams.
|
||||
MaintainAspectRatioSeamless,
|
||||
/// The texture coordinates range from 0 to 1.
|
||||
Stretch,
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKCoordModeV : uint8
|
||||
{
|
||||
/// The texture coordinates start at 0 and increase by 1 unit every meter.
|
||||
Metric,
|
||||
/// The texture coordinates are adjusted to the other dimensions to ensure the aspect ratio is maintained.
|
||||
MaintainAspectRatio,
|
||||
/// The texture coordinates range from 0 to 1.
|
||||
Stretch,
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKSpawnerSelectionMode : uint8
|
||||
{
|
||||
/// Pick one at random.
|
||||
Random,
|
||||
/// Pick the closest size.
|
||||
ClosestSize,
|
||||
/// Used in the AMRUKAnchorActorSpawner to use allow for a custom selection mode.
|
||||
Custom,
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKSpawnerScalingMode : uint8
|
||||
{
|
||||
/// Stretch each axis to exactly match the size of the Plane/Volume.
|
||||
Stretch,
|
||||
/// Scale each axis by the same amount to maintain the correct aspect ratio.
|
||||
UniformScaling,
|
||||
/// Scale the X and Y axes uniformly but the Z scale can be different.
|
||||
UniformXYScale,
|
||||
/// Don't perform any scaling.
|
||||
NoScaling,
|
||||
/// Used in the AMRUKAnchorActorSpawner to use allow for a custom scaling.
|
||||
Custom,
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKAlignMode : uint8
|
||||
{
|
||||
/// Do not perform any alignment
|
||||
None,
|
||||
/// Align the bottom of the bounding boxes and center the rest
|
||||
Default,
|
||||
/// Center the bounding box in the anchor bounding box
|
||||
CenterOnCenter,
|
||||
/// Align the bottom of the bounding boxes and center the rest
|
||||
BottomOnBottom,
|
||||
/// Align the top of the bounding boxes and center the rest
|
||||
TopOnTop,
|
||||
/// Align the left of the bounding boxes and center the rest
|
||||
LeftOnLeft,
|
||||
/// Align the right of the bounding boxes and center the rest
|
||||
RightOnRight,
|
||||
/// Align the front of the bounding boxes and center the rest
|
||||
FrontOnFront,
|
||||
/// Align the back of the bounding boxes and center the rest
|
||||
BackOnBack,
|
||||
/// Align the top to the bottom of the anchor bounding box and center the rest
|
||||
BottomOnTop,
|
||||
/// Align the bottom to the top of the anchor bounding box and center the rest
|
||||
TopOnBottom,
|
||||
/// Align the left to the right of the anchor bounding box and center the rest
|
||||
LeftOnRight,
|
||||
/// Align the right to the left of the anchor bounding box and center the rest
|
||||
RightOnLeft,
|
||||
/// Align the front to the back of the anchor bounding box and center the rest
|
||||
FrontOnBack,
|
||||
/// Align the back to the front of the anchor bounding box and center the rest
|
||||
BackOnFront,
|
||||
/// Use custom alignment mode
|
||||
Custom,
|
||||
};
|
||||
|
||||
/**
|
||||
* This enum is used to specify the component type, scene anchors can either have plane or volume components associated with them or both.
|
||||
*/
|
||||
UENUM(meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
|
||||
enum class EMRUKComponentType
|
||||
{
|
||||
/// No component type.
|
||||
None = 0 UMETA(Hidden),
|
||||
/// Plane component type.
|
||||
Plane = 1 << 0,
|
||||
/// Volume component type.
|
||||
Volume = 1 << 1,
|
||||
/// Mesh component type.
|
||||
Mesh = 1 << 2,
|
||||
/// All component types.
|
||||
All = Plane | Volume | Mesh UMETA(Hidden),
|
||||
};
|
||||
ENUM_CLASS_FLAGS(EMRUKComponentType);
|
||||
|
||||
/**
|
||||
* Describes a Raycast hit in the MRUK (Mixed Reality Utility Kit). This structure is created by the AMRUKAnchor::Raycast and AMRUKAnchor::RaycastAll methods. You can read the position where the raycast hit, the normal of the surface that was hit, and the distance from the origin to the raycast hit position.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct MRUTILITYKIT_API FMRUKHit
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* The position where the raycast hit.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FVector HitPosition = FVector::ZeroVector;
|
||||
|
||||
/**
|
||||
* The normal of the surface that was hit.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FVector HitNormal = FVector::ZeroVector;
|
||||
|
||||
/**
|
||||
* The distance between the origin of the ray to the hit position.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
float HitDistance = 0.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* Label filter to use in MRUK (Mixed Reality Utility Kit). You can use this to filter anchors by their labels.
|
||||
* use the IncludedLabels and ExcludedLabels list to specify which labels to include and exclude.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct MRUTILITYKIT_API FMRUKLabelFilter
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* If included labels is not empty then the anchor must have at
|
||||
* least one of the labels in this list.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TArray<FString> IncludedLabels;
|
||||
|
||||
/**
|
||||
* Anchors with any of the labels in this exclusion list
|
||||
* will be ignored.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TArray<FString> ExcludedLabels;
|
||||
|
||||
/**
|
||||
* Enum flags representing component types to include, by default include all component types.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit", meta = (Bitmask, BitmaskEnum = "EMRUKComponentType"))
|
||||
int32 ComponentTypes = static_cast<int32>(EMRUKComponentType::All);
|
||||
|
||||
/**
|
||||
* Check if the labels pass the given label filter
|
||||
* @param Labels The labels to check.
|
||||
* @return Whether the filter passes or not.
|
||||
*/
|
||||
bool PassesFilter(const TArray<FString>& Labels) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a configuration for adjusting the UV texture coordinates of a plane.
|
||||
*
|
||||
* It contains properties to specify an offset and scale to be applied to the UV texture coordinates.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct MRUTILITYKIT_API FMRUKPlaneUV
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* Offset applied to the UV texture coordinates.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
FVector2D Offset = FVector2D::ZeroVector;
|
||||
|
||||
/**
|
||||
* Scale applied to the UV texture coordinates.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
FVector2D Scale = FVector2D::UnitVector;
|
||||
};
|
||||
|
||||
/**
|
||||
* Texture coordinate modes for MRUK (Mixed Reality Utility Kit). You can use this to specify the texture coordinate mode for the U and V directions.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct MRUTILITYKIT_API FMRUKTexCoordModes
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* Texture Coordinate mode for the U direction.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKCoordModeU U = EMRUKCoordModeU::Metric;
|
||||
|
||||
/**
|
||||
* Texture Coordinate mode for the V direction.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKCoordModeV V = EMRUKCoordModeV::Metric;
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct represents a configuration for spawning an actor in the scene.
|
||||
*
|
||||
* It contains properties to specify the class of the actor to spawn, whether to match the aspect ratio of the volume,
|
||||
* whether to calculate the facing direction of the actor, and what scaling and alignment modes to apply to the actor.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct MRUTILITYKIT_API FMRUKSpawnActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* The class of actor to spawn.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TSubclassOf<AActor> Actor;
|
||||
|
||||
/**
|
||||
* When match aspect ratio is enabled then the actor will be rotated
|
||||
* to try and match the aspect ratio of the volume as closely as possible.
|
||||
* This is most useful for long and thin volumes, keep this disabled for
|
||||
* objects with an aspect ratio close to 1:1. Only applies to volumes.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
bool MatchAspectRatio = false;
|
||||
|
||||
/**
|
||||
* When calculate facing direction is enabled the actor will be rotated to
|
||||
* face away from the closest wall. If match aspect ratio is also enabled
|
||||
* then that will take precedence and it will be constrained to a choice
|
||||
* between 2 directions only. Only applies to volumes.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
bool CalculateFacingDirection = false;
|
||||
|
||||
/**
|
||||
* Set what scaling mode to apply to the actor. By default the actor will
|
||||
* be stretched to fit the size of the plane/volume. But in some cases
|
||||
* this may not be desirable and can be customized here.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKSpawnerScalingMode ScalingMode = EMRUKSpawnerScalingMode::Stretch;
|
||||
|
||||
/**
|
||||
* Set what alignment mode to apply to the actor. By default the actor will
|
||||
* be aligned that its bounding box matches the one from the anchor.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKAlignMode AlignMode = EMRUKAlignMode::Default;
|
||||
};
|
||||
|
||||
/**
|
||||
* This enum is used to specify the fallback behaviour when spawning an scene actor.
|
||||
* Specify whether to fallback to a procedural mesh or not.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKFallbackToProceduralOverwrite : uint8
|
||||
{
|
||||
/// Don't override the fallback to procedural standard behaviour.
|
||||
Default,
|
||||
/// Fallback to a procedural mesh.
|
||||
Fallback,
|
||||
/// Don't fallback to a procedural mesh.
|
||||
NoFallback,
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds a configuration for spawning a group of actors.
|
||||
*
|
||||
* It contains properties to specify a list of actors to choose from, the selection mode when multiple actors are specified,
|
||||
* and whether to fall back to spawning a procedural mesh if no actor class has been specified for this label.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct MRUTILITYKIT_API FMRUKSpawnGroup
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* List of actors to choose from, multiple actors can be specified and
|
||||
* the selection criteria will be determined by the SelectionMode option.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TArray<FMRUKSpawnActor> Actors;
|
||||
|
||||
/**
|
||||
* Set the selection mode when multiple different actors are specified.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKSpawnerSelectionMode SelectionMode = EMRUKSpawnerSelectionMode::Random;
|
||||
|
||||
/**
|
||||
* Control if there should happen a fallback to spawning a procedural mesh
|
||||
* in case no actor class has been specified for this label. The global
|
||||
* fallback behaviour can be specified in the AMRUKAnchorActorSpawner.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKFallbackToProceduralOverwrite FallbackToProcedural = EMRUKFallbackToProceduralOverwrite::Default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the settings for the MRUtilityKit plugin. This is Unreal specific and not part of the MR Utility Kit library.
|
||||
*/
|
||||
UCLASS(config = Game, defaultconfig)
|
||||
class MRUTILITYKIT_API UMRUKSettings : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UMRUKSettings(const FObjectInitializer& obj);
|
||||
|
||||
/**
|
||||
* When world locking is enabled the position of the VR Pawn will be adjusted each frame to ensure
|
||||
* the room anchors are where they should be relative to the camera position. This is necessary to
|
||||
* ensure the position of the virtual objects in the world do not get out of sync with the real world.
|
||||
*/
|
||||
UPROPERTY(config, EditAnywhere, Category = "MR Utility Kit")
|
||||
bool EnableWorldLock = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* MRUK (Mixed Reality Utility Kit) labels. These are the labels that are used by the MR Utility Kit library.
|
||||
* Those labels are used to identify the different types of objects in the scene, such as walls, floors, etc.
|
||||
*
|
||||
* Furthermore you also use those labels to filter, for queries and other tools such as the Raycast and RaycastAll methods.
|
||||
*/
|
||||
struct MRUTILITYKIT_API FMRUKLabels
|
||||
{
|
||||
static const FString Floor;
|
||||
static const FString WallFace;
|
||||
static const FString InvisibleWallFace;
|
||||
static const FString Ceiling;
|
||||
static const FString DoorFrame;
|
||||
static const FString WindowFrame;
|
||||
static const FString Couch;
|
||||
static const FString Table;
|
||||
static const FString Screen;
|
||||
static const FString Bed;
|
||||
static const FString Lamp;
|
||||
static const FString Plant;
|
||||
static const FString Storage;
|
||||
static const FString WallArt;
|
||||
static const FString GlobalMesh;
|
||||
static const FString Other;
|
||||
};
|
||||
|
||||
/**
|
||||
* This spawnmode controls how the MR Utility Kit handles spawning actors in the scene, either for all rooms, only for the current room or not at all.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKSpawnMode : uint8
|
||||
{
|
||||
/// Do not spawn anything on loading a scene or rooms.
|
||||
None = 0,
|
||||
|
||||
/// Will only take the current room into account. This enables legacy single room behaviour. Keep in mind that if your
|
||||
/// experience loads multiple rooms and you use that mode the behaviour might be undefined.
|
||||
CurrentRoomOnly,
|
||||
|
||||
/// Spawn in every room and keep on spawning whenever a new room was discovered.
|
||||
AllRooms
|
||||
};
|
||||
|
||||
/**
|
||||
* UE Module interface impelmentation
|
||||
*/
|
||||
class FMRUKModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
281
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKitAnchor.h
Normal file
281
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKitAnchor.h
Normal file
@@ -0,0 +1,281 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "MRUtilityKitAnchorActorSpawner.h"
|
||||
|
||||
#include "OculusXRAnchorTypes.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "MRUtilityKitAnchor.generated.h"
|
||||
|
||||
class AMRUKRoom;
|
||||
class UMRUKAnchorData;
|
||||
|
||||
/**
|
||||
* Represents an anchor in the Mixed Reality Utility Kit. This combines an Unreal actor with the scene anchor.
|
||||
* The actor is placed at the position of the anchor and the actor's rotation is set to match the rotation of the anchor.
|
||||
* Provides functions to check if a position is inside the volume or plane of the anchor, raycast against the anchor, etc...
|
||||
* @see https://developer.oculus.com/documentation/unreal/unreal-spatial-anchors/
|
||||
* for more information about anchors in the Mixed Reality Utility Kit.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Anchor"))
|
||||
class MRUTILITYKIT_API AMRUKAnchor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* The space handle of this anchor
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FOculusXRUInt64 SpaceHandle;
|
||||
|
||||
/**
|
||||
* The anchors UUID
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FOculusXRUUID AnchorUUID;
|
||||
|
||||
/**
|
||||
* The semantic classification of the anchor, also sometimes refered to as labels for short.
|
||||
* This can be for example FLOOR, COUCH, TABLE, SCREEN, BED, LAMP, etc...
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<FString> SemanticClassifications;
|
||||
|
||||
/**
|
||||
* If the anchor has a plane attached to it, this represents the bounds of that plane in
|
||||
* local coordinate space.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FBox2D PlaneBounds{ ForceInit };
|
||||
|
||||
/**
|
||||
* If the anchor has a plane attached to it, this represents the boundary of it in
|
||||
* local coordinate space. For rectangular boundaries this will be the same as the
|
||||
* PlaneBounds.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<FVector2D> PlaneBoundary2D;
|
||||
|
||||
/**
|
||||
* If the anchor has a volume attached to it, this represents the bounds of that volume in
|
||||
* local coordinate space.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FBox VolumeBounds{ ForceInit };
|
||||
|
||||
/**
|
||||
* Procedural mesh that is generated from the anchor geometry.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TObjectPtr<UProceduralMeshComponent> ProceduralMeshComponent;
|
||||
|
||||
/**
|
||||
* Pointer to the parent anchor, e.g. if this is a door or window frame the parent will
|
||||
* be a wall. If this is a screen it could have a desk parent.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<AMRUKAnchor> ParentAnchor;
|
||||
|
||||
/**
|
||||
* Array of all children attached to it, e.g. if this is a wall, it could have an array
|
||||
* of door/window frames. If this is a desk it could have an array of screens on it.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<TObjectPtr<AMRUKAnchor>> ChildAnchors;
|
||||
|
||||
/**
|
||||
* The room this anchor is placed in.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<AMRUKRoom> Room;
|
||||
|
||||
/**
|
||||
* Check if a 2D position is within the boundary of the plane. The position should be in
|
||||
* the local coordinate system NOT world coordinates.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool IsPositionInBoundary(const FVector2D& Position);
|
||||
|
||||
/**
|
||||
* Generate a uniform random position within the boundary of the plane.
|
||||
* @return The random position in local coordinate space.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
FVector GenerateRandomPositionOnPlane();
|
||||
|
||||
/**
|
||||
* Generate a uniform random position within the boundary of the plane from a random stream.
|
||||
* @param RandomStream A random generator used to generate the position on the plane.
|
||||
* @return The random position in local coordinate space.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
FVector GenerateRandomPositionOnPlaneFromStream(const FRandomStream& RandomStream);
|
||||
|
||||
/**
|
||||
* Cast a ray and return the closest hit against the volume and plane bounds.
|
||||
* @param Origin Origin The origin of the ray.
|
||||
* @param Direction Direction The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param OutHit The closest hit.
|
||||
* @param ComponentTypes The component types to include in the raycast.
|
||||
* @return Whether the ray hit anything
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool Raycast(const FVector& Origin, const FVector& Direction, float MaxDist, FMRUKHit& OutHit, UPARAM(meta = (Bitmask, BitmaskEnum = "EMRUKComponentType")) int32 ComponentTypes = 7 /* EMRUKComponentType::All */);
|
||||
static_assert(static_cast<int32>(EMRUKComponentType::All) == 7, "If this changes, please update the hardcoded default parameter in the Raycast function above");
|
||||
|
||||
/**
|
||||
* Cast a ray and collect hits against the volume and plane bounds. The order of the hits in the array is not specified.
|
||||
* @param Origin Origin The origin of the ray.
|
||||
* @param Direction Direction The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param OutHits The hits the ray collected.
|
||||
* @param ComponentTypes The component types to include in the raycast.
|
||||
* @return Whether the ray hit anything
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool RaycastAll(const FVector& Origin, const FVector& Direction, float MaxDist, TArray<FMRUKHit>& OutHits, UPARAM(meta = (Bitmask, BitmaskEnum = "EMRUKComponentType")) int32 ComponentTypes = 7 /* EMRUKComponentType::All */);
|
||||
static_assert(static_cast<int32>(EMRUKComponentType::All) == 7, "If this changes, please update the hardcoded default parameter in the RaycastAll function above");
|
||||
|
||||
/**
|
||||
* Attach a procedural mesh to the anchor. The mesh will match the size, position and shape of the volume and/or plane
|
||||
* if they are set.
|
||||
* @param PlaneUVAdjustments Scale and offset to apply to the UV texture coordinates. If more than one is specified
|
||||
* then multiple UV texture coordinates are created (up to 4) and adjustments applied to
|
||||
* each. This can be left empty in which case a single set of UV texture coordinates are
|
||||
* created in the range 0 to 1 for the plane.
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes.
|
||||
* @param GenerateCollision Whether to generate collision geometry or not
|
||||
* @param ProceduralMaterial Material to use on the procedural generated mesh.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "PlaneUVAdjustments", DeprecatedFunction, DeprecationMessage = "Use GenerateProceduralMesh instead."))
|
||||
void AttachProceduralMesh(TArray<FMRUKPlaneUV> PlaneUVAdjustments, const TArray<FString>& CutHoleLabels, bool GenerateCollision = true, UMaterialInterface* ProceduralMaterial = nullptr);
|
||||
|
||||
/**
|
||||
* Generate a procedural mesh for the anchor. The mesh will match the size, position and shape of the volume and/or plane
|
||||
* if they are set.
|
||||
* @param ProceduralMesh The procedural mesh component that should be used to store the generated mesh.
|
||||
* @param PlaneUVAdjustments Scale and offset to apply to the UV texture coordinates. If more than one is specified
|
||||
* then multiple UV texture coordinates are created (up to 4) and adjustments applied to
|
||||
* each. This can be left empty in which case a single set of UV texture coordinates are
|
||||
* created in the range 0 to 1 for the plane.
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes.
|
||||
* @param GenerateCollision Whether to generate collision geometry or not
|
||||
* @param Offset A offset to make the procedural mesh slightly bigger or smaller than the anchors volume/plane.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "PlaneUVAdjustments"))
|
||||
void GenerateProceduralAnchorMesh(UProceduralMeshComponent* ProceduralMesh, const TArray<FMRUKPlaneUV>& PlaneUVAdjustments, const TArray<FString>& CutHoleLabels, bool PreferVolume = false, bool GenerateCollision = true, double Offset = 0.0);
|
||||
|
||||
/**
|
||||
* Check if the anchor has the given label.
|
||||
* @param Label The label to check.
|
||||
* @return Whether the anchor has the given label.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool HasLabel(const FString& Label) const;
|
||||
|
||||
/**
|
||||
* Check if the anchor has any of the given labels.
|
||||
* @param Labels The labels to check.
|
||||
* @return Whether the anchor has any of the given labels.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool HasAnyLabel(const TArray<FString>& Labels) const;
|
||||
|
||||
/**
|
||||
* Check if the anchor passes the given label filter
|
||||
* @param LabelFilter The labels to check.
|
||||
* @return Whether the anchor has any of the given labels.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool PassesLabelFilter(const FMRUKLabelFilter& LabelFilter) const;
|
||||
|
||||
/**
|
||||
* Calculate the closest surface position on this anchor.
|
||||
* @param TestPosition The position in world space for which the closes surface position should be obtained.
|
||||
* @param OutSurfacePosition The closest surface position
|
||||
* @return The distance between TestPosition and OutSurfacePosition
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
double GetClosestSurfacePosition(const FVector& TestPosition, FVector& OutSurfacePosition);
|
||||
|
||||
/**
|
||||
* Checks if the given position is on or inside the volume bounds.
|
||||
* Floor, ceiling and wall anchors will be excluded from the search.
|
||||
* @param Position The position in world space to check
|
||||
* @param TestVerticalBounds Whether the vertical bounds should be checked or not
|
||||
* @param Tolerance Tolerance
|
||||
* @return The anchor the WorldPosition is in. A null pointer otherwise.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool IsPositionInVolumeBounds(const FVector& Position, bool TestVerticalBounds = true, double Tolerance = 0.0);
|
||||
|
||||
/**
|
||||
* Gets a natural “forward” direction for anchors; for planes, this is always Z-forward.
|
||||
* For volumes, it’s the X/Y cardinal axis that aligns best with the normal of the closest wall.
|
||||
* @return The forward facing direction.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
FVector GetFacingDirection() const;
|
||||
|
||||
/**
|
||||
* Spawn a mesh on the position of this anchor.
|
||||
* The actor should have Z as up, Y as right and X as forward.
|
||||
* @param ActorClass The Class to spawn at the anchors position.
|
||||
* @param MatchAspectRatio If true the actor will be rotated to best match the aspect ratio of the volume (applies to volumes only).
|
||||
* @param CalculateFacingDirection If true then actor will be rotated to face away from the closest wall (applies to volumes only).
|
||||
* @param ScalingMode Sets how to scale the actor to fit the size of the volume/plane.
|
||||
* @return The spawned actor or null if nothing was spawned.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "Use AMRUKAnchorActorSpawner instead."), Category = "MR Utility Kit")
|
||||
AActor* SpawnInterior(const TSubclassOf<class AActor>& ActorClass, bool MatchAspectRatio = false, bool CalculateFacingDirection = false, EMRUKSpawnerScalingMode ScalingMode = EMRUKSpawnerScalingMode::Stretch);
|
||||
|
||||
public:
|
||||
AMRUKAnchor(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
/**
|
||||
* Load the anchor from a MRUKAnchorData. This is used to load or update the anchor from device or from a JSON file.
|
||||
*
|
||||
* @param AnchorData The data to load from.
|
||||
* @return true if the anchor was loaded successfully.
|
||||
* @return false if the anchor could not be loaded.
|
||||
*/
|
||||
bool LoadFromData(UMRUKAnchorData* AnchorData);
|
||||
|
||||
/**
|
||||
* Attach a procedural mesh to the anchor. The mesh will match the size, position and shape of the volume and/or plane.
|
||||
*
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes. Example values: "WindowFrame", "DoorFrame".
|
||||
* @param GenerateCollision Whether to generate collision geometry or not.
|
||||
* @param ProceduralMaterial Material to use on the procedural generated mesh.
|
||||
*/
|
||||
void AttachProceduralMesh(const TArray<FString>& CutHoleLabels = {}, bool GenerateCollision = true, UMaterialInterface* ProceduralMaterial = nullptr);
|
||||
|
||||
TSharedRef<FJsonObject> JsonSerialize();
|
||||
|
||||
protected:
|
||||
void EndPlay(EEndPlayReason::Type Reason) override;
|
||||
|
||||
private:
|
||||
bool RayCastPlane(const FRay& LocalRay, float MaxDist, FMRUKHit& OutHit);
|
||||
bool RayCastVolume(const FRay& LocalRay, float MaxDist, FMRUKHit& OutHit);
|
||||
|
||||
struct TriangulatedMeshCache
|
||||
{
|
||||
TArray<FVector2D> Vertices;
|
||||
TArray<int32> Triangles;
|
||||
TArray<float> Areas;
|
||||
float TotalArea;
|
||||
|
||||
void Clear();
|
||||
};
|
||||
|
||||
UPROPERTY()
|
||||
AActor* Interior = nullptr;
|
||||
|
||||
TOptional<TriangulatedMeshCache> CachedMesh;
|
||||
};
|
||||
@@ -0,0 +1,322 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "MRUtilityKit.h"
|
||||
#include "MRUtilityKitAnchorActorSpawner.generated.h"
|
||||
|
||||
extern const FName GMRUK_PROCEDURAL_ANCHOR_MESH_TAG;
|
||||
|
||||
class AMRUKAnchor;
|
||||
/**
|
||||
* Spawns meshes on anchor positions.
|
||||
* If the out of the box functionality doesn't match your goals the AnchorActorSpawner provides way to inject
|
||||
* custom spawning logic into every step of it's spawning process by overwriting certain functions.
|
||||
* For this please take a look at SpawnAnchorActorsForRoom(), SpawnAnchorActorForLabel(), and SpawnAnchorActor().
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Anchor Actor Spawner"))
|
||||
class MRUTILITYKIT_API AMRUKAnchorActorSpawner : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInteriorSpawned, AMRUKRoom*, Room);
|
||||
|
||||
/**
|
||||
* Event that gets fired when the interior spawner finished spawning actors.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnInteriorSpawned OnActorsSpawned;
|
||||
|
||||
/**
|
||||
* Seed to use for the random generator that decideds wich actor class to
|
||||
* spawn if there a given multiple for a label.
|
||||
* negative values will have the effect to initialize the random generator
|
||||
* to a random seed.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
int AnchorRandomSpawnSeed = -1;
|
||||
|
||||
/**
|
||||
* Whether actors should be spawned automatically after the mixed reality
|
||||
* utility kit has been initialized. This should not be changed after the scene has been loaded.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
EMRUKSpawnMode SpawnMode = EMRUKSpawnMode::CurrentRoomOnly;
|
||||
|
||||
/**
|
||||
* Material to use when falling back to procedural material.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
UMaterialInterface* ProceduralMaterial = nullptr;
|
||||
|
||||
/**
|
||||
* Whether or not the spawner should fallback to procedural meshes in case no actor
|
||||
* class has been defined for a label. This behaviour can be overwritten on the label
|
||||
* basis in SpawnGroups.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool ShouldFallbackToProcedural = true;
|
||||
|
||||
/**
|
||||
* Labels for which holes should be created in the parents plane mesh.
|
||||
* E.g. if holes are needed in the walls where the windows and doors are, specify DOOR_FRAME and WINDOW_FRAME.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
TArray<FString> CutHoleLabels;
|
||||
|
||||
/**
|
||||
* A map of Actor classes to spawn for the given label.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
TMap<FString, FMRUKSpawnGroup> SpawnGroups{
|
||||
{ FMRUKLabels::Bed, {} },
|
||||
{ FMRUKLabels::Ceiling, {} },
|
||||
{ FMRUKLabels::Couch, {} },
|
||||
{ FMRUKLabels::DoorFrame, {} },
|
||||
{ FMRUKLabels::Floor, {} },
|
||||
{ FMRUKLabels::Lamp, {} },
|
||||
{ FMRUKLabels::Plant, {} },
|
||||
{ FMRUKLabels::Screen, {} },
|
||||
{ FMRUKLabels::Storage, {} },
|
||||
{ FMRUKLabels::Table, {} },
|
||||
{ FMRUKLabels::WallArt, {} },
|
||||
{ FMRUKLabels::WallFace, {} },
|
||||
{ FMRUKLabels::InvisibleWallFace, { {}, EMRUKSpawnerSelectionMode::Random, EMRUKFallbackToProceduralOverwrite::NoFallback } },
|
||||
{ FMRUKLabels::WindowFrame, {} },
|
||||
{ FMRUKLabels::Other, {} },
|
||||
};
|
||||
|
||||
/**
|
||||
* Spawns the meshes for the given labels above on the anchor positions in each room.
|
||||
* There might be multiple actor classes for a give label. If thats the case a actor class will be chosen radomly.
|
||||
* The seed for this random generator can be set by AnchorRandomSpawnSeed.
|
||||
* This function will be called automatically after the mixed reality utility kit initialized unless
|
||||
* the option SpawnOnStart is set to false.
|
||||
* If there is no actor class specified for a label then a procedural mesh matching the anchors volume and plane
|
||||
* will be generated.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void SpawnActors(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Return all spawned actors from the give room.
|
||||
* @param Room The room from which the actors should be returned
|
||||
* @param Actors The spawned actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void GetSpawnedActorsByRoom(AMRUKRoom* Room, TArray<AActor*>& Actors);
|
||||
|
||||
/**
|
||||
* Return all spawned actors from all rooms.
|
||||
* @param Actors The spawned actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void GetSpawnedActors(TArray<AActor*>& Actors);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This method gets called by the AnchorActorSpawner when it wants to spawn actors and procedural meshes in the room.
|
||||
* It's possible to overwrite this function in Blueprint or C++ to implement custom spawning logic.
|
||||
* The protected methods in the AnchorActorSpawner contain helper functions which can be useful when implementing
|
||||
* a custom spawning logic. When implementing a custom spawning logic you may want to use SpawnAnchorActor() to spawn
|
||||
* the actual actor and take care of it's orientation and scaling to match the anchors bounds.
|
||||
* @param Room The room to spawn actors for.
|
||||
* @param RandomStream A random stream to be used with the random selection mode.
|
||||
* @return A list of all spawned actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnAnchorActorsInRoom(AMRUKRoom* Room, const FRandomStream& RandomStream);
|
||||
|
||||
virtual TArray<AActor*> SpawnAnchorActorsInRoom_Implementation(AMRUKRoom* Room, const FRandomStream& RandomStream);
|
||||
|
||||
/**
|
||||
* This method gets called by the default implementation of the SpawnAnchorActorsInRoom() for every label that should spawn a actor.
|
||||
* By overwriting this function it is possible to inject custom spawning logic for actors on a per label basis.
|
||||
* When implementing a custom spawning logic you may want to use SpawnAnchorActor() to spawn the actual actor and take care of it's
|
||||
* orientation and scaling to match the anchors bounds.
|
||||
* @param Anchor The anchor to spawn a actor for.
|
||||
* @param Label The label to spawn a actor for.
|
||||
* @param SpawnGroup Information on which actor should be spawned.
|
||||
* @param RandomStream A random stream for implementing the random selection logic.
|
||||
* @return The spawned actor.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "MR Utility Kit")
|
||||
AActor* SpawnAnchorActorForLabel(AMRUKAnchor* Anchor, const FString& Label, const FMRUKSpawnGroup& SpawnGroup, const FRandomStream& RandomStream);
|
||||
|
||||
virtual AActor* SpawnAnchorActorForLabel_Implementation(AMRUKAnchor* Anchor, const FString& Label, const FMRUKSpawnGroup& SpawnGroup, const FRandomStream& RandomStream);
|
||||
|
||||
/**
|
||||
* This method gets called by the default implementation of SpawnAnchorActorForLabel() to spawn the anchor and orient and scale
|
||||
* it correct to the given anchor. If you are planning to implement a custom spawning logic you likely want to use this function
|
||||
* in the end to actually spawn the actor as it takes care of orientation and scaling of the actor with regards to the anchor bounds.
|
||||
* @param Anchor The anchor to spawn the actor for.
|
||||
* @param SpawnActor Information on which actor should be spawned.
|
||||
* @return The spawned actor.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "MR Utility Kit")
|
||||
AActor* SpawnAnchorActor(AMRUKAnchor* Anchor, const FMRUKSpawnActor& SpawnActor);
|
||||
|
||||
virtual AActor* SpawnAnchorActor_Implementation(AMRUKAnchor* Anchor, const FMRUKSpawnActor& SpawnActor);
|
||||
|
||||
/**
|
||||
* Override this method to inject custom scaling logic into the orientation process of an actor. The scale that this method returns
|
||||
* gets used to scale the actor that will be spawned.
|
||||
* @param Anchor The anchor for which the actor gets spawned.
|
||||
* @param SpawnedActor The actor that gets spawned.
|
||||
* @param StretchedScale The scale that would need to be applied to the actor to make it match with the bounding box of the anchor.
|
||||
* In case it's a plane anchor only the X and Y component of the scale are relevant.
|
||||
* @return The scale that should be applied to the actor. In case it's a plane anchor only the X and Y component are relevant.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "MR Utility Kit")
|
||||
FVector ComputeCustomScaling(AMRUKAnchor* Anchor, AActor* SpawnedActor, const FVector& StretchedScale);
|
||||
|
||||
virtual FVector ComputeCustomScaling_Implementation(AMRUKAnchor* Anchor, AActor* SpawnedActor, const FVector& StretchedScale);
|
||||
|
||||
/**
|
||||
* Override this method to inject custom actor selection logic. This will be called for every actor that gets spawned by the AMRUKAnchorActorSpawner.
|
||||
* @param Anchor The anchor for which a actor should be spawned
|
||||
* @param SpawnGroup The group of actors that can be used for decision making.
|
||||
* @param RandomStream A random stream to randomize outputs if necessary.
|
||||
* @param OutSpawnActor The actor which should be spawned.
|
||||
* @return Whether the selection process was successful or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool SelectSpawnActorCustom(AMRUKAnchor* Anchor, const FMRUKSpawnGroup& SpawnGroup, const FRandomStream& RandomStream, FMRUKSpawnActor& OutSpawnActor);
|
||||
|
||||
virtual bool SelectSpawnActorCustom_Implementation(AMRUKAnchor* Anchor, const FMRUKSpawnGroup& SpawnGroup, const FRandomStream& RandomStream, FMRUKSpawnActor& OutSpawnActor);
|
||||
|
||||
/**
|
||||
* Override this method to inject custom scaling logic into the orientation process of an actor. The scale that this method returns
|
||||
* gets used to scale the actor that will be spawned.
|
||||
* @param Anchor The anchor for which the actor gets spawned.
|
||||
* @param Actor The actor that gets spawned.
|
||||
* @param ChildBounds the rotated bounding box of the actor that should be spawned. For planes only X and Y components are relevant.
|
||||
* @param Scale The scale that will be applied to the actor that will be spawned in place of the anchor. For planes only X and Y components are relevant.
|
||||
* @return The offset that should be applied to the actor. In case it's a plane anchor only the X and Y component are relevant.
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "MR Utility Kit")
|
||||
FVector ComputeCustomAlign(AMRUKAnchor* Anchor, AActor* Actor, const FBox& ChildBounds, const FVector& Scale);
|
||||
|
||||
virtual FVector ComputeCustomAlign_Implementation(AMRUKAnchor* Anchor, AActor* Actor, const FBox& ChildBounds, const FVector& Scale);
|
||||
|
||||
/**
|
||||
* Check if for the given SpawnGroup a procedural mesh should be spawned.
|
||||
* @param SpawnGroup The spawn group to check
|
||||
* @return Whether a procedural mesh should be spawned or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool ShouldAnchorFallbackToProceduralMesh(const FMRUKSpawnGroup& SpawnGroup) const;
|
||||
|
||||
/**
|
||||
* Check if there should be spawned a actor for the given label. This function may return false in case
|
||||
* the spawner should fallback to a procedural mesh.
|
||||
* @param Anchor The anchor where the actor should be spawned
|
||||
* @param Label The label of the anchor
|
||||
* @param OutSpawnGroup Will be set in case a actor should be spawned
|
||||
* @return Whether or not a actor should be spawned for the anchor
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool ShouldSpawnActorForAnchor(AMRUKAnchor* Anchor, const FString& Label, FMRUKSpawnGroup& OutSpawnGroup) const;
|
||||
|
||||
/**
|
||||
* Spawn a procedural mesh for all walls if no wall actor is given to the spawner.
|
||||
* This will take care of generating seamless UVs for the walls.
|
||||
* @param Room The room to spawn in.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnProceduralMeshesOnWallsIfNoWallActorGiven(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Spawn a procedural mesh for the floor if no floor actor is given to the spawner.
|
||||
* @param Room The room to spawn in.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AActor* SpawnProceduralMeshOnFloorIfNoFloorActorGiven(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Spawn a procedural mesh for the ceiling if no ceiling actor is given to the spawner.
|
||||
* @param Room The room to spawn in.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AActor* SpawnProceduralMeshOnCeilingIfNoCeilingActorGiven(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Spawn a procedural mesh for the given anchor if the settings on the AnchorActorSpawner say so.
|
||||
* @param Anchor The anchor for which the procedural mesh should be spawned
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AActor* SpawnProceduralMeshForAnchorIfNeeded(AMRUKAnchor* Anchor);
|
||||
|
||||
/**
|
||||
* Spawn procedural meshes for every anchor that needs them. Including walls, ceiling and floor.
|
||||
* The method determines if procedural mesh should be spawned or not based on the settings of the
|
||||
* AnchorActorSpawner.
|
||||
* @param Room The room to spawn in.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnProceduralMeshesInRoom(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Select the SpawnActor based on the size that matches best the anchor bounds.
|
||||
* @param Anchor The anchor for which a actor should be spawned.
|
||||
* @param SpawnGroup The spawn group.
|
||||
* @param OutSpawnActor The found spawn actor.
|
||||
* @return True if a SpawnActor could be found. Otherwise, false.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool SelectSpawnActorClosestSize(AMRUKAnchor* Anchor, const FMRUKSpawnGroup& SpawnGroup, FMRUKSpawnActor& OutSpawnActor);
|
||||
|
||||
/**
|
||||
* Select the SpawnActor randomly
|
||||
* @param SpawnGroup The spawn group.
|
||||
* @param RandomStream The random stream to use for the random selection.
|
||||
* @param OutSpawnActor The found spawn actor.
|
||||
* @return True if a SpawnActor could be found. Otherwise, false.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool SelectSpawnActorRandom(const FMRUKSpawnGroup& SpawnGroup, const FRandomStream& RandomStream, FMRUKSpawnActor& OutSpawnActor);
|
||||
|
||||
/**
|
||||
* Select a SpawnActor from the SpawnGroup with respect to the given selection mode in SpawnGroup.
|
||||
* @param Anchor The anchor for which the actor should be spawned.
|
||||
* @param SpawnGroup The spawn group.
|
||||
* @param RandomStream The random stream
|
||||
* @param OutSpawnActor The found spawn actor
|
||||
* @return True if a spawn actor has been found. Otherwise, false.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool SelectSpawnActorFromSpawnGroup(AMRUKAnchor* Anchor, const FMRUKSpawnGroup& SpawnGroup, const FRandomStream& RandomStream, FMRUKSpawnActor& OutSpawnActor);
|
||||
|
||||
/**
|
||||
* Orient and scale the given actor to the anchors plane or volume bounds.
|
||||
* @param Anchor The anchor
|
||||
* @param Actor The actor which should be oriented and scaled to the given anchor.
|
||||
* @param ScalingMode The scaling mode that should be used when doing the matching.
|
||||
* @param bCalculateFacingDirection Whether or not the facing direction of the anchor should be calculated and used for the orientation process.
|
||||
* @param bMatchAspectRatio Whether or not the aspect ratio of the anchor should be matched.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void AttachAndFitActorToAnchor(AMRUKAnchor* Anchor, AActor* Actor, EMRUKSpawnerScalingMode ScalingMode, EMRUKAlignMode AlignMode, bool bCalculateFacingDirection, bool bMatchAspectRatio);
|
||||
|
||||
void BeginPlay() override;
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomCreated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomUpdated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomRemoved(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void RemoveActors(AMRUKRoom* Room);
|
||||
|
||||
private:
|
||||
// Room UUID to spawned actors in this room
|
||||
TMap<AMRUKRoom*, TArray<AActor*>> SpawnedActors;
|
||||
|
||||
int32 LastSeed = -1;
|
||||
};
|
||||
@@ -0,0 +1,173 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "Kismet/BlueprintAsyncActionBase.h"
|
||||
#include "OculusXRAnchorTypes.h"
|
||||
#include "MRUtilityKitBPLibrary.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FMRUKMeshSegment
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
TArray<FVector> Positions;
|
||||
TArray<int32> Indices;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the scene async from device.
|
||||
*/
|
||||
UCLASS()
|
||||
class MRUTILITYKIT_API UMRUKLoadFromDevice : public UBlueprintAsyncActionBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMRUKLoaded);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (WorldContext = "WorldContext", BlueprintInternalUseOnly = "true"
|
||||
))
|
||||
static UMRUKLoadFromDevice* LoadSceneFromDeviceAsync(const UObject* WorldContext
|
||||
);
|
||||
|
||||
virtual void Activate() override;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FMRUKLoaded Success;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FMRUKLoaded Failure;
|
||||
|
||||
private:
|
||||
UFUNCTION(CallInEditor)
|
||||
void OnSceneLoaded(bool Succeeded);
|
||||
|
||||
TWeakObjectPtr<UWorld> World = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixed Reality Utility Kit Blueprint Function Library.
|
||||
* See functions for further information.
|
||||
*/
|
||||
UCLASS()
|
||||
class MRUTILITYKIT_API UMRUKBPLibrary : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* Load the global mesh from the device.
|
||||
* @param SpaceHandle Space handle of the room.
|
||||
* @param OutProceduralMesh Procedural mesh to load the triangle data in.
|
||||
* @param LoadCollision Whether to generate collision or not.
|
||||
* @param WorldContext Context of the world.
|
||||
* @return Whether the load was successful or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (WorldContext = "WorldContext"))
|
||||
static bool LoadGlobalMeshFromDevice(FOculusXRUInt64 SpaceHandle, UProceduralMeshComponent* OutProceduralMesh, bool LoadCollision, const UObject* WorldContext);
|
||||
|
||||
/**
|
||||
* Load the global mesh from a JSON string.
|
||||
* @param JsonString The string containing the JSON.
|
||||
* @param AnchorUUID Anchor UUID of the room
|
||||
* @param OutProceduralMesh Procedural mesh to load the triangle data in.
|
||||
* @param LoadCollision Whether to generate collision or not
|
||||
* @return Whether the load was successful or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
static bool LoadGlobalMeshFromJsonString(const FString& JsonString, FOculusXRUUID AnchorUUID, UProceduralMeshComponent* OutProceduralMesh, bool LoadCollision);
|
||||
|
||||
/**
|
||||
* (Re)Calculate Normals and Tangents of the given procedural mesh.
|
||||
* @param Mesh The procedural mesh.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
static void RecalculateProceduralMeshAndTangents(class UProceduralMeshComponent* Mesh);
|
||||
|
||||
/**
|
||||
* Check if the current Unreal Engine is the fork of Meta.
|
||||
* @return Whether its the fork or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "MR Utility Kit")
|
||||
static bool IsUnrealEngineMetaFork();
|
||||
|
||||
/**
|
||||
* Compute the centroid of a polygon that is defined by the points.
|
||||
* The centroid may be outside of the polygon in case the polygon is non convex.
|
||||
* @param PolygonPoints Points that define the polygon.
|
||||
* @return The centroid.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "MR Utility Kit")
|
||||
static FVector2D ComputeCentroid(const TArray<FVector2D>& PolygonPoints);
|
||||
|
||||
/**
|
||||
* In Unreal Engine, scale is always applied in the local space to avoid any skew.
|
||||
* This means that if you have a component which has a 90 degree rotation and is scaled, or any of its
|
||||
* children are scaled then the scale axes will not be applied as you would expect. This is can make it
|
||||
* very awkward to work with when trying to scale the actors to fit within the scene volumes. To work around
|
||||
* this problem, this function will attempt to adjust the scale axes recursively to match the expected behaviour.
|
||||
* This will only work reliably if the rotations involved are 90 degrees, if they are not then it will pick the closest axis.
|
||||
* @param SceneComponent The component where the scale should be set
|
||||
* @param UnRotatedScale The scale you would like to have without considering any rotations
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
static void SetScaleRecursivelyAdjustingForRotation(USceneComponent* SceneComponent, const FVector& UnRotatedScale);
|
||||
|
||||
/**
|
||||
* Compute the direction that faces away from the closest wall of the given anchor.
|
||||
* @param Anchor The anchor for which the direction should be computed.
|
||||
* @param OutCardinalAxisIndex The index of the computed cardinal axis. Can be either 0, 1, 2 or 3
|
||||
* @param ExcludedAxes Axes to exclude in the computation. Can contain 0, 1, 2, 3
|
||||
* @return The direction
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
static FVector ComputeDirectionAwayFromClosestWall(const AMRUKAnchor* Anchor, int& OutCardinalAxisIndex, const TArray<int> ExcludedAxes);
|
||||
|
||||
/**
|
||||
* Construct a 2D texture from a render target.
|
||||
* @param RenderTarget2D The render target from which the texture should be created.
|
||||
* @param Outer The (optional) outer object for the created texture.
|
||||
* @param TexName Name for the new texture.
|
||||
* @return The newly created texture.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
static UTexture2D* ConstructTexture2D(UTextureRenderTarget2D* RenderTarget2D, UObject* Outer, const FString& TexName);
|
||||
|
||||
/**
|
||||
* Extract a column from a matrix.
|
||||
* @param Matrix The matrix to use.
|
||||
* @param Index The column index.
|
||||
* @return The column of the matrix.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "MR Utility Kit")
|
||||
static FLinearColor GetMatrixColumn(const FMatrix& Matrix, int32 Index);
|
||||
|
||||
/**
|
||||
* Compute a grid by taking into account the room box geometry. E.g. create evenly spaced points on ceiling, floor and walls.
|
||||
* @param Room The room to use
|
||||
* @param MaxPointsCount The maximum number of points
|
||||
* @param PointsPerUnitX The density of points on the X axis
|
||||
* @param PointsPerUnitY The density of points on the Y axis
|
||||
* @param bIncludeFloor Whether or not to include the floor
|
||||
* @param bIncludeCeiling Whether or not to include the ceiling
|
||||
* @param bIncludeWalls Whether or not to include the walls
|
||||
* @return The computed points
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
static TArray<FVector> ComputeRoomBoxGrid(const AMRUKRoom* Room, int32 MaxPointsCount, double PointsPerUnitX = 1.0, double PointsPerUnitY = 1.0);
|
||||
|
||||
/**
|
||||
* Create mesh segments from the given mesh. This can be used for creating a destructible mesh system.
|
||||
* @param MeshPositions The mesh positions that should be segmented
|
||||
* @param MeshIndices The mesh indices that should be segmented
|
||||
* @param SegmentationPoints A set of points that should be used to calculate the segments
|
||||
* @param ReservedMin Reserved space from the lower part of the bound box
|
||||
* @param ReservedMax Reserved space from the upper part of the bounding box
|
||||
* @param OutSegments The segmented meshes that have been created from the given mesh
|
||||
* @param OutReservedSegment
|
||||
*/
|
||||
static void CreateMeshSegmentation(const TArray<FVector>& MeshPositions, const TArray<uint32>& MeshIndices,
|
||||
const TArray<FVector>& SegmentationPoints, const FVector& ReservedMin, const FVector& ReservedMax,
|
||||
TArray<FMRUKMeshSegment>& OutSegments, FMRUKMeshSegment& OutReservedSegment);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "MRUtilityKitBlobShadowComponent.generated.h"
|
||||
|
||||
/**
|
||||
* Adds a blob shadow below the actor.
|
||||
* The blob shadow will position and resize itself automatically during runtime.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent, DisplayName = "MR Utility Kit Blob Shadow Component"))
|
||||
class MRUTILITYKIT_API UMRUKBlobShadowComponent : public UStaticMeshComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* Controls the look of the blob shadow corners (0 = squared corners, 1 = rounded corners).
|
||||
*/
|
||||
UPROPERTY(Category = "MR Utility Kit|Aspect", EditAnywhere, BlueprintReadWrite, meta = (UIMin = "0", UIMax = "1"))
|
||||
float Roundness = 1.0f;
|
||||
|
||||
/**
|
||||
* Controls the look of the blob shadow alpha (0 = fully opaque, 1 = gradient from the center).
|
||||
*/
|
||||
UPROPERTY(Category = "MR Utility Kit|Aspect", EditAnywhere, BlueprintReadWrite, meta = (UIMin = "0", UIMax = "1"))
|
||||
float Gradient = 0.544f;
|
||||
|
||||
/**
|
||||
* Controls the curve of the blob shadow alpha gradient (only available if Gradient > 0).
|
||||
*/
|
||||
UPROPERTY(Category = "MR Utility Kit|Aspect", EditAnywhere, BlueprintReadWrite, meta = (EditCondition = "Gradient > 0"))
|
||||
float GradientPower = 3.0f;
|
||||
|
||||
/**
|
||||
* Increase or decrease the calculated blob shadow size by a fixed amount.
|
||||
*/
|
||||
UPROPERTY(Category = "MR Utility Kit", EditAnywhere, BlueprintReadWrite)
|
||||
float ExtraExtent = -10.0f;
|
||||
|
||||
/**
|
||||
* Maximum distance the actor can be away from the ground until the blob shadow is not shown anymore.
|
||||
*/
|
||||
UPROPERTY(Category = "MR Utility Kit", EditAnywhere, BlueprintReadWrite)
|
||||
float MaxVerticalDistance = 100.f;
|
||||
|
||||
/**
|
||||
* Distance from the ground until the blob shadow starts to fade.
|
||||
*/
|
||||
UPROPERTY(Category = "MR Utility Kit", EditAnywhere, BlueprintReadWrite)
|
||||
float FadeDistance = 20.f;
|
||||
|
||||
/**
|
||||
* Only callable in the editor from the scene, will update the blob shadow size, position and material parameters
|
||||
* to give a preview how the blob shadow would look like.
|
||||
*/
|
||||
UFUNCTION(Category = "MR Utility Kit", CallInEditor)
|
||||
void UpdatePlaneSizeAndPosition();
|
||||
|
||||
public:
|
||||
UMRUKBlobShadowComponent();
|
||||
|
||||
void BeginPlay() override;
|
||||
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
void ComputeOwner2DBounds(FVector& Origin, FVector2D& Extent, double& Yaw) const;
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
UMaterialInstanceDynamic* DynMaterial;
|
||||
};
|
||||
139
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKitData.h
Normal file
139
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKitData.h
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "OculusXRRoomLayoutManagerComponent.h"
|
||||
#include "Dom/JsonValue.h"
|
||||
#include "OculusXRAnchorsRequests.h"
|
||||
#include "MRUtilityKitData.generated.h"
|
||||
|
||||
/**
|
||||
* Actor to help finding the localization of actors.
|
||||
* It gets a list of all anchor queries that should be localized
|
||||
* and checks every tick if the anchor localization is there.
|
||||
* When the localization is complete, it will emit the event OnComplete.
|
||||
*
|
||||
* NOTE: Normally this should be a async task. However, the anchor data
|
||||
* can only be queried in game thread.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Hidden)
|
||||
class MRUTILITYKIT_API AMRUKLocalizer : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnComplete, bool, Success);
|
||||
|
||||
/**
|
||||
* Event that gets fired when all anchors have been localized.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnComplete OnComplete;
|
||||
|
||||
TArray<class UMRUKAnchorData*> AnchorsData;
|
||||
|
||||
AMRUKLocalizer();
|
||||
|
||||
void Tick(float DeltaTime) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* A datastrcture to hold the data of a single anchor. It also provides functions to load the data from device or json.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Hidden)
|
||||
class MRUTILITYKIT_API UMRUKAnchorData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FOculusXRAnchorsDiscoverResult SpaceQuery;
|
||||
FTransform Transform;
|
||||
|
||||
FBox2D PlaneBounds;
|
||||
FBox VolumeBounds;
|
||||
|
||||
TArray<FString> SemanticClassifications;
|
||||
TArray<FVector2D> PlaneBoundary2D;
|
||||
|
||||
bool NeedAnchorLocalization = false;
|
||||
|
||||
void LoadFromDevice(const FOculusXRAnchorsDiscoverResult& AnchorsDiscoverResult);
|
||||
void LoadFromJson(const FJsonValue& Value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load room data from device.
|
||||
* When all room data has been loaded, the OnComplete event will be fired.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Hidden)
|
||||
class MRUTILITYKIT_API UMRUKRoomData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnComplete, bool, Success);
|
||||
|
||||
/**
|
||||
* Event that gets fired after all room data has been loaded.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnComplete OnComplete;
|
||||
|
||||
FOculusXRAnchorsDiscoverResult SpaceQuery;
|
||||
FOculusXRRoomLayout RoomLayout;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<TObjectPtr<UMRUKAnchorData>> AnchorsData;
|
||||
|
||||
UPROPERTY()
|
||||
AMRUKLocalizer* LocalizationActor = nullptr;
|
||||
|
||||
class UMRUKSceneData* SceneData;
|
||||
|
||||
void LoadFromDevice(UMRUKSceneData* Data, const FOculusXRAnchorsDiscoverResult& AnchorsDiscoverResult);
|
||||
void LoadFromJson(UMRUKSceneData* Data, const FJsonValue& Value);
|
||||
|
||||
private:
|
||||
void FinishQuery(bool Success);
|
||||
void RoomDataLoadedComplete(EOculusXRAnchorResult::Type Result);
|
||||
void RoomDataLoadedIncrementalResults(const TArray<FOculusXRAnchorsDiscoverResult>& DiscoverResults);
|
||||
UFUNCTION()
|
||||
void AnchorsInitialized(bool Success);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load scene data from device.
|
||||
* When all scene data has been loaded, the OnComplete event will be fired.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Hidden)
|
||||
class MRUTILITYKIT_API UMRUKSceneData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnComplete, bool, Success);
|
||||
|
||||
/**
|
||||
* Event that gets fired after all scene data has been loaded.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnComplete OnComplete;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<TObjectPtr<UMRUKRoomData>> RoomsData;
|
||||
|
||||
void LoadFromDevice();
|
||||
void LoadFromJson(const FString& Json);
|
||||
|
||||
private:
|
||||
int32 NumRoomsLeftToInitialize = 0;
|
||||
bool AnyRoomFailed = false;
|
||||
|
||||
void FinishQuery(bool Success);
|
||||
void SceneDataLoadedResult(EOculusXRAnchorResult::Type Result);
|
||||
void SceneDataLoadedComplete(const TArray<FOculusXRAnchorsDiscoverResult>& DiscoverResults);
|
||||
UFUNCTION()
|
||||
void RoomQueryComplete(bool Success);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "MRUtilityKitDebugComponent.generated.h"
|
||||
|
||||
/**
|
||||
* Various debugging utilities for the scene.
|
||||
* This component can for example attached to the player pawn. The various methods can
|
||||
* then be called on input from the pawn.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (BlueprintSpawnableComponent, DisplayName = "MR Utility Kit Debug Component"))
|
||||
class MRUTILITYKIT_API UMRUKDebugComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* The gizmo to show when visualizing an anchor.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TSubclassOf<AActor> GizmoActorClass = nullptr;
|
||||
|
||||
/**
|
||||
* The text to show when visualizing an anchor.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TSubclassOf<AActor> TextActorClass = nullptr;
|
||||
|
||||
/**
|
||||
* The scale that should be applied to the gizmo before displaying it.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FVector GizmoScale = FVector(0.1);
|
||||
|
||||
/**
|
||||
* The scale that should be applied to the text before displaying it.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FVector TextScale = FVector(0.5);
|
||||
|
||||
/**
|
||||
* Shoot a ray and display the anchors coordinate system and labels that was hit by the ray if any.
|
||||
* Call HideAnchor() to get rid of the displayed anchor.
|
||||
* @param Origin The ray origin.
|
||||
* @param Direction The ray direction.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void ShowAnchorAtRayHit(const FVector& Origin, const FVector& Direction);
|
||||
|
||||
/**
|
||||
* Hide the current anchor. This method needs only to be called to hide the anchor
|
||||
* that was displayed by ShowAnchorAtRayHit().
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void HideAnchor();
|
||||
|
||||
/**
|
||||
* Shoot a ray and display the anchors space that was hit by the ray if any.
|
||||
* Call HideAnchorSpace() to get rid of the displayed anchor space.
|
||||
* @param Origin The ray origin.
|
||||
* @param Direction The ray direction.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void ShowAnchorSpaceAtRayHit(const FVector& Origin, const FVector& Direction);
|
||||
|
||||
/**
|
||||
* Hide the current anchor space actor. This method needs only to be called to hide the
|
||||
* anchor space that was displayed by ShowAnchorAtRayHit().
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void HideAnchorSpace();
|
||||
|
||||
public:
|
||||
UMRUKDebugComponent();
|
||||
|
||||
void BeginPlay() override;
|
||||
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
TObjectPtr<AActor> ActiveGizmoActor = nullptr;
|
||||
UPROPERTY()
|
||||
TObjectPtr<AActor> ActiveTextActor = nullptr;
|
||||
UPROPERTY()
|
||||
TObjectPtr<AActor> ActiveAnchorSpaceActor = nullptr;
|
||||
|
||||
void OrientTextActorToPlayer() const;
|
||||
};
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MRUtilityKit.h"
|
||||
#include "MRUtilityKitBPLibrary.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "Tasks/Task.h"
|
||||
#include "MRUtilityKitDestructibleMesh.generated.h"
|
||||
|
||||
/**
|
||||
* Destructible mesh component. Creates mesh segments for the given geometry.
|
||||
* The segments will be created async.
|
||||
* In addition, its possible to define areas that are indestructible.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent, DisplayName = "MR Utility Kit Destructible Mesh Component"))
|
||||
class MRUTILITYKIT_API UMRUKDestructibleMeshComponent : public UProceduralMeshComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnMeshesGenerated);
|
||||
|
||||
UMRUKDestructibleMeshComponent(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnMeshesGenerated OnMeshesGenerated;
|
||||
|
||||
/**
|
||||
* Material to display on the global mesh
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
UMaterialInterface* GlobalMeshMaterial;
|
||||
|
||||
/**
|
||||
* Area on the top of the mesh that should be indestructible.
|
||||
* The area is given in centimeters 1.0 == 1 cm.
|
||||
* -1.0 means no reserved area.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double ReservedTop = -1.0;
|
||||
|
||||
/**
|
||||
* Area on the bottom of the mesh that should be indestructible.
|
||||
* The area is given in centimeters 1.0 == 1 cm
|
||||
* -1.0 means no reserved area.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double ReservedBottom = 30.0;
|
||||
|
||||
/**
|
||||
* Segment the given geometry into smaller chunks. For each chunk a procedural mesh component will be spawned and attached to the owning actor.
|
||||
* @param MeshPositions Positions of the mesh to segment
|
||||
* @param MeshIndices Indices of the mesh to segment
|
||||
* @param SegmentationPoints Points to use to determine the segments.
|
||||
*/
|
||||
void SegmentMesh(const TArray<FVector>& MeshPositions, const TArray<uint32>& MeshIndices, const TArray<FVector>& SegmentationPoints);
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
private:
|
||||
UE::Tasks::TTask<TPair<TArray<FMRUKMeshSegment>, FMRUKMeshSegment>> TaskResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* Actor that constructs a destructible mesh for the given room
|
||||
* The actor will automatically attach to the global mesh anchor of the given room to take it location and orientation.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent, DisplayName = "MR Utility Kit Destructible Global Mesh"))
|
||||
class MRUTILITYKIT_API AMRUKDestructibleGlobalMesh : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AMRUKDestructibleGlobalMesh();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
UMRUKDestructibleMeshComponent* DestructibleMeshComponent;
|
||||
|
||||
/**
|
||||
* Density of mesh segments on the X axis.
|
||||
* Increase this value to get smaller cracks in the global mesh.
|
||||
* Decrease this value to get bigger cracks in the global mesh.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double PointsPerUnitX = 1.0;
|
||||
|
||||
/**
|
||||
* How many segmentation points should be created at a maximum.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
int MaxPointsCount = 256;
|
||||
|
||||
/**
|
||||
* Density of mesh segments on the Y axis.
|
||||
* Increase this value to get smaller cracks in the global mesh.
|
||||
* Decrease this value to get bigger cracks in the global mesh.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double PointsPerUnitY = 1.0;
|
||||
|
||||
/**
|
||||
* Create a destructible mesh for the given room. If the global mesh has not yet been loaded
|
||||
* this function will attempt to load the global mesh from the device.
|
||||
* @param Room The room
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void CreateDestructibleMesh(AMRUKRoom* Room = nullptr);
|
||||
|
||||
/**
|
||||
* Remove a segment of the global mesh. Takes care of not removing the reserved global mesh segment.
|
||||
* @param Mesh The mesh to remove
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void RemoveGlobalMeshSegment(UPrimitiveComponent* Mesh);
|
||||
};
|
||||
|
||||
/**
|
||||
* The destructible global mesh spawner allows to spawn (automatically) destructible global meshes
|
||||
* when new rooms are created.
|
||||
* A destructible global mesh is a version of the global mesh that can be destructed during runtime.
|
||||
* The bulk of the work is performed in UDestructibleMeshComponent. It will perform on start a one time
|
||||
* preprocessing step to segment the given global mesh into smaller chunks. After that the chunks can be used
|
||||
* during the game and removed (e.g. with ray casts) at any time during the game simulating as if the global
|
||||
* mesh would crack down. To enhance the visual quality when cracking the (e.g. removing mesh chunks) global mesh
|
||||
* a particle system could be used. The system allows to define areas that should be non destructible.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent, DisplayName = "MR Utility Kit Destructible Global Mesh Spawner"))
|
||||
class MRUTILITYKIT_API AMRUKDestructibleGlobalMeshSpawner : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* Whether destructible meshes should be spawned automatically.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
EMRUKSpawnMode SpawnMode = EMRUKSpawnMode::CurrentRoomOnly;
|
||||
|
||||
/**
|
||||
* Material to display on the global mesh
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
UMaterialInterface* GlobalMeshMaterial;
|
||||
|
||||
/**
|
||||
* Density of mesh segments on the X axis.
|
||||
* Increase this value to get smaller cracks in the global mesh.
|
||||
* Decrease this value to get bigger cracks in the global mesh.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double PointsPerUnitX = 1.0;
|
||||
|
||||
/**
|
||||
* How many segmentation points should be created at a maximum.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
int MaxPointsCount = 256;
|
||||
|
||||
/**
|
||||
* Density of mesh segments on the Y axis.
|
||||
* Increase this value to get smaller cracks in the global mesh.
|
||||
* Decrease this value to get bigger cracks in the global mesh.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double PointsPerUnitY = 1.0;
|
||||
|
||||
/**
|
||||
* Area on the top of the mesh that should be indestructible.
|
||||
* The area is given in centimeters 1.0 == 1 cm
|
||||
* -1.0 means no reserved area.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double ReservedTop = -1.0;
|
||||
|
||||
/**
|
||||
* Area on the bottom of the mesh that should be indestructible.
|
||||
* The area is given in centimeters 1.0 == 1 cm
|
||||
* -1.0 means no reserved area.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double ReservedBottom = 30.0;
|
||||
|
||||
void BeginPlay() override;
|
||||
|
||||
/**
|
||||
* Find the destructible mesh that has been spawned for the given room.
|
||||
* @param Room Room to look for the destructible mesh
|
||||
* @return The destructible mesh
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKDestructibleGlobalMesh* FindDestructibleMeshForRoom(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Add new destructible mesh for the given room. A mesh will only get spawned if no
|
||||
* destructible mesh has been spawned for the room yet.
|
||||
* @param Room The room.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKDestructibleGlobalMesh* AddDestructibleGlobalMesh(AMRUKRoom* Room);
|
||||
|
||||
private:
|
||||
TMap<AMRUKRoom*, AMRUKDestructibleGlobalMesh*> SpawnedMeshes;
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomCreated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomRemoved(AMRUKRoom* Room);
|
||||
};
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MRUtilityKit.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "MRUtilityKitDistanceMapGenerator.generated.h"
|
||||
|
||||
const FName GMRUK_DISTANCE_MAP_ACTOR_TAG = TEXT("DistanceMapActor");
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKDistanceMapGenerationMode : uint8
|
||||
{
|
||||
// Do not generate a distance map
|
||||
None,
|
||||
/// Generate distance map only for the free space. E.g. The floor inside the room.
|
||||
FreeSpace,
|
||||
/// Generate the distance map only for the occupied space. E.g. outside the room and inside scene objects.
|
||||
OccupiedSpace,
|
||||
/// Generate the distance map for free space and occupied space.
|
||||
AllSpace,
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a distance map that can be used in materials to calculate the distance to various objects.
|
||||
* This can enable interesting effects. With the distance map you can get the distance from scene objects
|
||||
* or walls in a material shader.
|
||||
*
|
||||
* The Jump Flood Algorithm is used to generate the distance map. This is fast enough to regenerate
|
||||
* every tick.
|
||||
*
|
||||
* To capture a distance map after a room has been loaded call CaptureDistanceMap().
|
||||
* It will return a captured distance map. In case you already called CaptureDistanceMap()
|
||||
* you can receive the last captured distance map with GetDistanceMap(). No other setup is required.
|
||||
*
|
||||
* This class will create procedural meshes for every anchor to create a mask. These meshes have their
|
||||
* visibility set to scene capture only. That however means that if you place a scene capture component yourself
|
||||
* that the meshes will show up in your scene capture component. The actors that have the procedural meshes
|
||||
* attached are tagged with GMRUK_DISTANCE_MAP_ACTOR_TAG. In case you don't want them to show up in your
|
||||
* scene capture you can hide them by receiving all these actors with the tag GMRUK_DISTANCE_MAP_ACTOR_TAG
|
||||
* and add these to the scene captures hidden actors.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Distance Map Generator"))
|
||||
class MRUTILITYKIT_API AMRUKDistanceMapGenerator : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnReady);
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnReady OnReady;
|
||||
|
||||
/**
|
||||
* The mode in which the final distance map should be generated.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKDistanceMapGenerationMode DistanceMapGenerationMode = EMRUKDistanceMapGenerationMode::FreeSpace;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class USceneComponent* Root;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class USceneCaptureComponent2D* SceneCapture2D;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKSpawnMode SpawnMode = EMRUKSpawnMode::CurrentRoomOnly;
|
||||
|
||||
/**
|
||||
* First render target for jump flood algorithm.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UCanvasRenderTarget2D* RenderTarget1;
|
||||
|
||||
/**
|
||||
* Second render target for jump flood algorithm.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UCanvasRenderTarget2D* RenderTarget2;
|
||||
|
||||
/**
|
||||
* Render target for the final distance map
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UCanvasRenderTarget2D* DistanceMapRenderTarget;
|
||||
|
||||
/**
|
||||
* Material to render a mask that gets used to calculate the distance map.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UMaterialInterface* MaskMaterial;
|
||||
|
||||
/**
|
||||
* Material that executes a pass of the jump flood algorithm.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UMaterialInterface* JFPassMaterial;
|
||||
|
||||
/**
|
||||
* Material to render final distance map
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UMaterialInterface* DistanceMapFreeSpaceMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UMaterialInterface* DistanceMapOccupiedSpaceMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UMaterialInterface* DistanceMapAllSpaceMaterial;
|
||||
|
||||
/**
|
||||
* Capture the distance map.
|
||||
* @return The captured distance map.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
UTexture* CaptureDistanceMap();
|
||||
|
||||
/**
|
||||
* Create mask meshes for the given room.
|
||||
* These mask meshes are needed for the distance map to be rendered. It should only be called once before
|
||||
* CaptureDistanceMap in case the SpawnMode has been set to None.
|
||||
* The operation that this function executes is expensive. It only needs to be called after the room has been
|
||||
* created or updated.
|
||||
* @param Room The room for which the masked meshes should be created.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void CreateMaskMeshesForRoom(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Remove mask meshes for the given room.
|
||||
* This function should only be executed when SpawnMode is set to None.
|
||||
* It only needs to be called after a room has been removed.
|
||||
* @param Room The room for which the masked meshes should be removed.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void RemoveMaskMeshesFromRoom(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Return the captured distance map. Be sure to call CaptureDistanceMap() before
|
||||
* @return The captured distance map.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
UTexture* GetDistanceMap() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
UCanvasRenderTarget2D* GetDistanceMapRenderTarget() const;
|
||||
|
||||
/**
|
||||
* Retrieve the view info from the scene capture. This is useful for re projection of
|
||||
* the distance map in a material.
|
||||
* @return The view info.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
FMinimalViewInfo GetSceneCaptureView() const;
|
||||
|
||||
public:
|
||||
AMRUKDistanceMapGenerator();
|
||||
|
||||
protected:
|
||||
void BeginPlay() override;
|
||||
|
||||
private:
|
||||
TMap<AMRUKRoom*, TArray<AActor*>> SpawnedMaskMeshes;
|
||||
|
||||
int32 DistanceMapRT = -1;
|
||||
|
||||
UPROPERTY()
|
||||
class UMaterialInstanceDynamic* JFPassMaterialInstance = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
class UMaterialInstanceDynamic* DistanceMapFreeSpaceMaterialInstance = nullptr;
|
||||
UPROPERTY()
|
||||
class UMaterialInstanceDynamic* DistanceMapOccupiedSpaceMaterialInstance = nullptr;
|
||||
UPROPERTY()
|
||||
class UMaterialInstanceDynamic* DistanceMapAllSpaceMaterialInstance = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
UMaterialInterface* SceneObjectMaskMaterial;
|
||||
|
||||
UPROPERTY()
|
||||
UMaterialInterface* FloorMaskMaterial;
|
||||
|
||||
void CaptureInitialSceneMask();
|
||||
void RenderDistanceMap();
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomCreated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomUpdated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
AActor* CreateMaskMeshOfAnchor(AMRUKAnchor* Anchor);
|
||||
|
||||
UFUNCTION()
|
||||
AActor* UpdateMaskMeshOfAnchor(AMRUKAnchor* Anchor);
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Containers/Array.h"
|
||||
#include "Math/Vector2D.h"
|
||||
|
||||
MRUTILITYKIT_API void MRUKTriangulatePolygon(const TArray<TArray<FVector2f>>& Polygons, TArray<FVector2D>& Vertices, TArray<int32>& Indices);
|
||||
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/SceneComponent.h"
|
||||
#include "MRUtilityKitGridSliceResizer.generated.h"
|
||||
|
||||
UENUM(BlueprintType, Meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
|
||||
enum class EMRUKScaleCenterMode : uint8
|
||||
{
|
||||
None = 0 UMETA(Hidden),
|
||||
XAxis = 1,
|
||||
YAxis = 2,
|
||||
ZAxis = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* The GridSliceResizerComponent is a versatile tool designed to maintain the proportions of
|
||||
* specific areas of 3D meshes while allowing others to stretch during scaling. This component
|
||||
* should replace the static mesh component, rather than being used in conjunction with it.
|
||||
*
|
||||
* The concept of the GridSliceResizerComponent is similar to the popular 9-Slice-Scaling technique
|
||||
* used in 2D graphics, which keeps the borders of sprites unstretched while the inner rectangle is
|
||||
* stretched. In essence, the GridSliceResizerComponent is a 27-Slice-Scaler for 3D meshes.
|
||||
*
|
||||
* The component operates by dividing the bounding box of a 3D mesh into 27 cuboids, as illustrated below.
|
||||
* Not all cuboids are visible in this picture. Only the once that are front facing:
|
||||
*
|
||||
* +-----+-----------+-----+
|
||||
* /_____/___________/_____/|
|
||||
* /_____/___________/_____/||
|
||||
* / / / /|||
|
||||
* +-----+-----------+-----+ |||
|
||||
* | A | B | C |/|||
|
||||
* +-----+-----------+-----+ |||
|
||||
* | | | | |||
|
||||
* | D | E | F | |||
|
||||
* | | | |/||/
|
||||
* +-----+-----------+-----+ |/
|
||||
* | G | H | I | /
|
||||
* +-----+-----+-----+-----+
|
||||
*
|
||||
* The scaling behaviour is as follows (assuming all other faces of the bounding box are divided as the
|
||||
* front facing one):
|
||||
*
|
||||
* Center Cuboid (E): Vertices within this cuboid stretch on two axes (Y, Z).
|
||||
* Corner Cuboids (A, C, G, I): These cuboids do not stretch on any axis.
|
||||
* Middle Cuboids (B, H): These cuboids stretch horizontally but not vertically.
|
||||
* Middle Cuboids (D, F): These cuboids stretch vertically but not horizontally.
|
||||
*
|
||||
* The slicing areas are defined by the SlicerPivotOffset and BorderXNegative, BorderXPositive, etc.
|
||||
* These border values range from 0 to 1 and extend from the mesh's pivot (which may be offset by SlicerPivotOffset)
|
||||
* to the maximum or minimum of the bounding box's axis.
|
||||
* If all borders are set to 1, the mesh will stretch like a regular mesh during scaling. If set to 0, no stretching
|
||||
* will occur. Typically, you'll want the pivot in the middle of the mesh and the borders set to around 0.8.
|
||||
*
|
||||
* You can visualize the borders and pivot in the Actor editor preview using bDebugDrawPivot, bDebugDrawBorderX, etc.
|
||||
*
|
||||
* This component is only compatible with static meshes that have CPU access enabled. Ensure you enable CPU
|
||||
* access in the static mesh editor.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent, DisplayName = "MR Utility Kit Grid Slice Resizer Component"))
|
||||
class MRUTILITYKIT_API UMRUKGridSliceResizerComponent : public USceneComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* The static mesh to slice. Make sure to enable CPU access on it.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
class UStaticMesh* Mesh;
|
||||
|
||||
/**
|
||||
* Slice border for the negative X axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit|Slices", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
double BorderXNegative = 1.0;
|
||||
|
||||
/**
|
||||
* Slice border for the positive X axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit|Slices", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
double BorderXPositive = 1.0;
|
||||
|
||||
/**
|
||||
* Slice border for the negative Y axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit|Slices", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
double BorderYNegative = 1.0;
|
||||
|
||||
/**
|
||||
* Slice border for the positive Y axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit|Slices", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
double BorderYPositive = 1.0;
|
||||
|
||||
/**
|
||||
* Slice border for the negative Z axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit|Slices", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
double BorderZNegative = 1.0;
|
||||
|
||||
/**
|
||||
* Slice border for the positive Z axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit|Slices", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
double BorderZPositive = 1.0;
|
||||
|
||||
/**
|
||||
* How much the meshes pivot should be offset when applying the slice borders.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
FVector SlicerPivotOffset;
|
||||
|
||||
/**
|
||||
* This parameter determines whether the center part of the object should be scaled.
|
||||
* If set to false, the center vertices will remain stationary. This is particularly useful when
|
||||
* you want to maintain the proportions of certain geometrical features in the center part, such
|
||||
* as a doorknob. By keeping the center vertices in place, you can avoid unwanted stretching effects,
|
||||
* resulting in a more visually appealing outcome.
|
||||
* However, it's important to note that for a convincing visual effect, the texture applied to the object should also not stretch.
|
||||
* If you encounter issues with texture stretching, consider adding an additional loop cut.
|
||||
* This can help maintain the texture's proportions and prevent it from distorting.
|
||||
* In case the mesh gets scaled down and some of the center vertices fall outside of the scaled down center
|
||||
* all vertices that are inside the center will be scaled down uniformly.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit", meta = (Bitmask, BitmaskEnum = "/Script/MRUtilityKit.EMRUKScaleCenterMode"))
|
||||
uint8 ScaleCenterMode = 0;
|
||||
|
||||
/**
|
||||
* Whether or not a collision mesh should be created for the static mesh.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool bGenerateCollision = true;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
/**
|
||||
* Show the pivot of the mesh that gets used for the slice borders.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool bDebugDrawPivot = false;
|
||||
|
||||
/**
|
||||
* Show the slice borders on the X axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool bDebugDrawBorderX = false;
|
||||
|
||||
/**
|
||||
* Show the slice borders on the Y axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool bDebugDrawBorderY = false;
|
||||
|
||||
/**
|
||||
* Show the slice borders on the Z axis.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool bDebugDrawBorderZ = false;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Slice the mesh. This gets automatically called whenever
|
||||
* the scale of the owning Actor changes.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void SliceMesh();
|
||||
|
||||
public:
|
||||
UMRUKGridSliceResizerComponent();
|
||||
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
virtual void OnRegister() override;
|
||||
|
||||
#if WITH_EDITOR
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class FMRUKGridSliceResizerSpec;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
class UProceduralMeshComponent* ProcMesh;
|
||||
|
||||
FVector ResizerScale = FVector::OneVector;
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MRUtilityKitRoom.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "MRUtilityKitGuardian.generated.h"
|
||||
|
||||
/**
|
||||
* The Guardian is a procedural mesh that is generated from the anchor geometry and has the guardian material applied.
|
||||
* It is used to show the player where the walls and furniture. It prevents the player from walking into walls or furniture.
|
||||
* It uses TryGetClosestSurfacePosition to determine if the player is close to the walls or furniture.
|
||||
* This can be beneficial if your application has a full VR mode.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Guardian Actor"))
|
||||
class MRUTILITYKIT_API AMRUKGuardian : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* Procedural mesh that is generated from the anchor geometry and has the guardian material applied.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<UProceduralMeshComponent> GuardianMeshComponent;
|
||||
|
||||
/**
|
||||
* Attaches the procedural mesh component to this actor.
|
||||
* @param GuardianMesh The mesh to attach.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void CreateGuardian(UProceduralMeshComponent* GuardianMesh);
|
||||
|
||||
public:
|
||||
AMRUKGuardian(const FObjectInitializer& ObjectInitializer);
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MRUtilityKit.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "MRUtilityKitGuardian.h"
|
||||
#include "MRUtilityKitGuardianSpawner.generated.h"
|
||||
|
||||
class AMRUKRoom;
|
||||
|
||||
/**
|
||||
* This class helps with spawning a guardian if the player gets close to any furniture or walls. This is useful if your application has a full VR mode.
|
||||
* It can spawn a guardian for each room in the scene. It can also spawn a guardian for the current room only.
|
||||
* For details about the guardian see the AMRUKGuardian class.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Guardian"))
|
||||
class MRUTILITYKIT_API AMRUKGuardianSpawner : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AMRUKGuardianSpawner();
|
||||
|
||||
/**
|
||||
* Whether SpawnGuardian() should be called automatically after the mixed reality utility kit
|
||||
* has been initialized.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
EMRUKSpawnMode SpawnMode = EMRUKSpawnMode::CurrentRoomOnly;
|
||||
|
||||
/**
|
||||
* How close the camera needs to come to a surface before the guardian appears.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
double GuardianDistance = 0.75;
|
||||
|
||||
/**
|
||||
* Whether the fading value should be calculated for the shader or not.
|
||||
If fading is not needed this can save performance.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool EnableFade = true;
|
||||
|
||||
/**
|
||||
* Spawn the guardian. This will get called automatically after the mixed reality utility kit has
|
||||
* been initialized if SpawnMode is set to something other than None.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void SpawnGuardians(AMRUKRoom* Room);
|
||||
|
||||
/**
|
||||
* Set the guardian material to a different one.
|
||||
* @param Material The guardian material.
|
||||
*/
|
||||
UFUNCTION(BlueprintSetter, Category = "MR Utility Kit")
|
||||
void SetGuardianMaterial(UMaterialInstance* Material);
|
||||
|
||||
/**
|
||||
* Set the density of the grid.
|
||||
* @param Density The grid density.
|
||||
*/
|
||||
UFUNCTION(BlueprintSetter, Category = "MR Utility Kit")
|
||||
void SetGridDensity(double Density);
|
||||
|
||||
public:
|
||||
void Tick(float DeltaSeconds) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The material to use for the guardian. It needs to have a scalar parameter Fade
|
||||
* and a vector parameter WallScale. If this material is not set a default one
|
||||
* will be used.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintSetter = SetGuardianMaterial, Category = "MR Utility Kit")
|
||||
TObjectPtr<UMaterialInstance> GuardianMaterial = nullptr;
|
||||
|
||||
/**
|
||||
* How dense the grid should be.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintSetter = SetGridDensity, Category = "MR Utility Kit")
|
||||
double GridDensity = 2.0;
|
||||
|
||||
void BeginPlay() override;
|
||||
#if WITH_EDITOR
|
||||
void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Room UUID to spawned actors in this room
|
||||
TMap<AMRUKRoom*, TArray<AMRUKGuardian*>> SpawnedGuardians;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UMaterialInstanceDynamic> DynamicGuardianMaterial = nullptr;
|
||||
|
||||
UFUNCTION()
|
||||
void DestroyGuardians(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomCreated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomUpdated(AMRUKRoom* Room);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRoomRemoved(AMRUKRoom* Room);
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "MRUtilityKitLightDispatcher.generated.h"
|
||||
|
||||
/**
|
||||
* If you want to have highlights from lights over passthrough use this actor to collect all point lights in the scene and send them to the M_Highlights material.
|
||||
* It lights and sends them to a highlight material, which can be used to achieve highlights over Passthrough.
|
||||
* The highlight effect is achieved by using a material parameter collection.
|
||||
* See the PTRL Sample Project for an example of how to use this.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Light Dispatcher"))
|
||||
class MRUTILITYKIT_API AMRUKLightDispatcher : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* The material parameter collection in which to fill lights data.
|
||||
* This parameter collection gets then send to the shader.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
class UMaterialParameterCollection* Collection;
|
||||
|
||||
/**
|
||||
* Whether all point lights should be fetched automatically at BeginPlay().
|
||||
* The automatic fetching only works for PointLightActors. Actors that have PointLightComponents
|
||||
* attached to them will not be detected. These should be specified in AdditionalActorsToLookForPointLightComponents.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
bool ShouldFetchPointLightsAtBeginPlay = true;
|
||||
|
||||
/**
|
||||
* List of actor(s) that contain a PointLightComponent that should contribute to the highlight effect.
|
||||
* Use AddAdditionalPointLightActor to add actors during runtime.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TArray<AActor*> AdditionalActorsToLookForPointLightComponents;
|
||||
|
||||
/**
|
||||
* PointLightActors to use for the highlight effect (not available if "Fetch Point Lights At Begin Play" is true).
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditCondition = "!ShouldFetchPointLightsAtBeginPlay"), Category = "MR Utility Kit")
|
||||
TArray<class APointLight*> ManualPointLights;
|
||||
|
||||
/**
|
||||
* Add a actor to the AdditionalActorsToLookForPointLightComponents list.
|
||||
* This should be used during runtime instead of adding actors directly to AdditionalActorsToLookForPointLightComponents.
|
||||
* @param Actor Actor to add to AdditionalActorsToLookForPointLightComponents.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void AddAdditionalPointLightActor(AActor* Actor);
|
||||
|
||||
/**
|
||||
* Only callable in the editor from the scene, will update the linked parameter collection with the info
|
||||
* of the point lights in the scene (based on the parameters), updating the highlight effect in the process.
|
||||
* This is meant to preview the effect in the editor.
|
||||
*/
|
||||
UFUNCTION(CallInEditor, Category = "MR Utility Kit")
|
||||
void ForceUpdateCollection();
|
||||
|
||||
public:
|
||||
AMRUKLightDispatcher();
|
||||
|
||||
void Tick(float DeltaSeconds) override;
|
||||
|
||||
void FillParameterCollection();
|
||||
|
||||
protected:
|
||||
UPROPERTY(Transient)
|
||||
TArray<class UPointLightComponent*> PointLightComponents;
|
||||
|
||||
void BeginPlay() override;
|
||||
|
||||
void FillPointLights();
|
||||
void AddPointLightsFromActor(const AActor* Actor);
|
||||
};
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "MRUtilityKitRoom.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "MRUtilityKitPositionGenerator.generated.h"
|
||||
|
||||
/**
|
||||
* Holds the settings which are used for generating random positions. It offers several attributes to be configured, such as
|
||||
* which room to use, what actor to spawn, scene labels to use and much more. This struct is used by the position generator.
|
||||
* @see AMRUtilityKitPositionGenerator
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FMRUKRandomSpawnSettings
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* When the scene data is loaded, this controls what room(s) the position generator will be used in.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKRoomFilter RoomFilter = EMRUKRoomFilter::CurrentRoomOnly;
|
||||
|
||||
/**
|
||||
* When an actor instance is reference here, this actor will be moved around.
|
||||
* If you'd need to spawn new actors, use ActorClass.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
AActor* ActorInstance = nullptr;
|
||||
|
||||
/**
|
||||
* Reference the specific actor class for spawning.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TSubclassOf<AActor> ActorClass;
|
||||
|
||||
/**
|
||||
* How many instances to spawn at the random generated position per room.
|
||||
* Note: If using an ActorInstance this property is ignored
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
int SpawnAmount = 8;
|
||||
|
||||
/**
|
||||
* Maximum number of times to attempt spawning/moving an object before giving up.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
int MaxIterations = 1000;
|
||||
|
||||
/**
|
||||
* The type of surface by which to limit the generation.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
EMRUKSpawnLocation SpawnLocations = EMRUKSpawnLocation::Floating;
|
||||
|
||||
/**
|
||||
* The labels to include or exclude.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
FMRUKLabelFilter Labels;
|
||||
|
||||
/**
|
||||
* If enabled then the spawn position will be checked to make sure there is no overlap with physics colliders including themselves.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
bool CheckOverlaps = true;
|
||||
|
||||
/**
|
||||
* Required free space for the object.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
float OverrideBounds = -1;
|
||||
|
||||
/**
|
||||
* The CollisionChannel to use.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
TEnumAsByte<ECollisionChannel> CollisionChannel = ECC_WorldStatic;
|
||||
|
||||
/**
|
||||
* The clearance distance required in front of the surface in order for it to be considered a valid spawn position.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
float SurfaceClearanceDistance = 0.1f;
|
||||
};
|
||||
|
||||
/**
|
||||
* Position generator that can be used to generate random positions on the surface in a specific room or any room.
|
||||
*
|
||||
* It contains methods to generate random positions on the surface of a given spawn location,
|
||||
* while ensuring that the generated positions are at least `MinDistanceToEdge` away from any edges,
|
||||
* if it should run on start when MRUK initializes and follow the other settings specified in `SpawnSettings`.
|
||||
*/
|
||||
UCLASS()
|
||||
class MRUTILITYKIT_API AMRUtilityKitPositionGenerator : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
static bool CanSpawnBox(const UWorld* World, const FBox& Box, const FVector& SpawnPosition, const FQuat& SpawnRotation, const FCollisionQueryParams& QueryParams, ECollisionChannel CollisionChannel);
|
||||
|
||||
/**
|
||||
* Generates a set of random positions on the surface of a given spawn location, while ensuring that the generated positions
|
||||
* are at least `MinDistanceToEdge` away from any edges and follow the other settings specified in `SpawnSettings`.
|
||||
* @param OutTransforms An array of transforms representing the generated positions.
|
||||
* @return A boolean value indicating whether valid positions were found. If no valid positions could be found, `OutTransforms` will be empty.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool GenerateRandomPositionsOnSurface(TArray<FTransform>& OutTransforms);
|
||||
|
||||
/**
|
||||
* Generates a set of random positions on the surface of a given spawn location, while ensuring that the generated positions
|
||||
* are at least `MinDistanceToEdge` away from any edges and follow the other settings specified in `SpawnSettings` in the
|
||||
* give room.
|
||||
* @param Room The room where the positions should be generated in.
|
||||
* @param OutTransforms An array of transforms representing the generated positions.
|
||||
* @return A boolean value indicating whether valid positions were found. If no valid positions could be found, `OutTransforms` will be empty.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool GenerateRandomPositionsOnSurfaceInRoom(AMRUKRoom* Room, TArray<FTransform>& OutTransforms);
|
||||
|
||||
/**
|
||||
* Whether GenerateRandomPositionsOnSurface() should be called automatically after the mixed reality utility kit has been initialized
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
bool RunOnStart = true;
|
||||
|
||||
/**
|
||||
* Settings that should be used when generating random positions.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
FMRUKRandomSpawnSettings RandomSpawnSettings;
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
private:
|
||||
virtual UWorld* GetTickableGameObjectWorld() const { return GetWorld(); }
|
||||
|
||||
UFUNCTION()
|
||||
void SceneLoaded(bool Success);
|
||||
};
|
||||
481
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKitRoom.h
Normal file
481
Plugins/MetaXR/Source/MRUtilityKit/Public/MRUtilityKitRoom.h
Normal file
@@ -0,0 +1,481 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "MRUtilityKit.h"
|
||||
#include "OculusXRAnchorTypes.h"
|
||||
#include "MRUtilityKitRoom.generated.h"
|
||||
|
||||
class UMRUKRoomData;
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKSpawnLocation : uint8
|
||||
{
|
||||
Floating UMETA(DisplayName = "Floating"), // Spawn somewhere floating in the free space within the room
|
||||
AnySurface UMETA(DisplayName = "Any surface"), // Spawn on any surface (i.e. a combination of all 3 options below)
|
||||
VerticalSurfaces UMETA(DisplayName = "Vertical surfaces"), // Spawn only on vertical surfaces such as walls, windows, wall art, doors, etc...
|
||||
OnTopOfSurface UMETA(DisplayName = "On top of surfaces"), // Spawn on surfaces facing upwards such as ground, top of tables, beds, couches, etc...
|
||||
HangingDown UMETA(DisplayName = "Hanging down") // Spawn on surfaces facing downwards such as the ceiling
|
||||
};
|
||||
|
||||
enum class EMRUKBoxSide : uint8
|
||||
{
|
||||
XPos,
|
||||
XNeg,
|
||||
YPos,
|
||||
YNeg,
|
||||
ZPos,
|
||||
ZNeg,
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKRoomFilter : uint8
|
||||
{
|
||||
None,
|
||||
CurrentRoomOnly,
|
||||
AllRooms
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to use when determining the position and rotation for the best pose.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EMRUKPositioningMethod : uint8
|
||||
{
|
||||
/**
|
||||
* Center the object on the surface.
|
||||
*/
|
||||
Center = 0,
|
||||
/**
|
||||
* Snap the object to edge which is closest to the user.
|
||||
*/
|
||||
Edge,
|
||||
/**
|
||||
* Use the location where the ray hit the object as the location.
|
||||
* The rotation is dependent on the objects shape. For example for walls
|
||||
* the hit normal from the raycast will be used. For floors the rotation
|
||||
* will be towards the user and for volumes that got hit on the top the
|
||||
* rotation will be towards the longest edge that is nearest to the player.
|
||||
*/
|
||||
Default,
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an anchor with its corresponding plane UVs in the Mixed Reality Utility Kit.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FMRUKAnchorWithPlaneUVs
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* A readonly reference to the anchor.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<AMRUKAnchor> Anchor;
|
||||
|
||||
/**
|
||||
* An array of plane UVs that correspond to the anchor.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<FMRUKPlaneUV> PlaneUVs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a room in the MRUK.
|
||||
* A room holds (MRUK)Anchors as children for entities such as Desk, Floor, Ceiling, Walls, etc. Those entities are defined with their label.
|
||||
* It also provides events which will be triggered when an anchor has been added, removed or updated from space setup.
|
||||
*
|
||||
* This room class calculates different helper properties such as Outline, Edges, Bounds
|
||||
* and provides room functions as helpers such as determine if a point in space (XYZ) is inside the room, generating points on surfaces, generate points in room (floating), raycasts and more.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Room Actor"))
|
||||
class MRUTILITYKIT_API AMRUKRoom : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAnchorUpdated, AMRUKAnchor*, Anchor);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAnchorCreated, AMRUKAnchor*, Anchor);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAnchorRemoved, AMRUKAnchor*, Anchor);
|
||||
|
||||
/**
|
||||
* The space handle of this anchor
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FOculusXRUInt64 SpaceHandle;
|
||||
|
||||
/**
|
||||
* The anchors UUID
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FOculusXRUUID AnchorUUID;
|
||||
|
||||
/**
|
||||
* Event that gets fired if a anchor in this room was updated.
|
||||
* E.g. volume or plane changed.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnAnchorUpdated OnAnchorUpdated;
|
||||
|
||||
/**
|
||||
* Event that gets fired if a new anchor was created in this room.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnAnchorCreated OnAnchorCreated;
|
||||
|
||||
/**
|
||||
* Event that gets fired if a anchor gets removed from this room.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnAnchorRemoved OnAnchorRemoved;
|
||||
|
||||
/**
|
||||
* Bounds of the room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
FBox RoomBounds;
|
||||
|
||||
/**
|
||||
* Edges of the room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<FVector> RoomEdges;
|
||||
|
||||
/**
|
||||
* The floor anchor of this room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<AMRUKAnchor> FloorAnchor;
|
||||
|
||||
/**
|
||||
* The ceiling anchor of this room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<AMRUKAnchor> CeilingAnchor;
|
||||
|
||||
/**
|
||||
* The wall anchors of this room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<TObjectPtr<AMRUKAnchor>> WallAnchors;
|
||||
|
||||
/**
|
||||
* The global mesh anchor of this room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TObjectPtr<AMRUKAnchor> GlobalMeshAnchor;
|
||||
|
||||
/**
|
||||
* All anchors which are possible to sit on.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<TObjectPtr<AMRUKAnchor>> SeatAnchors;
|
||||
|
||||
/**
|
||||
* All anchors of this room.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<TObjectPtr<AMRUKAnchor>> AllAnchors;
|
||||
|
||||
/**
|
||||
* Check whether the position is inside the room or not.
|
||||
* @param Position The position in world space to check.
|
||||
* @param TestVerticalBounds Whether the room should be constrained by vertical bounds or not in the check.
|
||||
* @return Whether the position is inside the room or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool IsPositionInRoom(const FVector& Position, bool TestVerticalBounds = true);
|
||||
|
||||
/**
|
||||
* Generate a uniform random position within the room.
|
||||
* @param OutPosition Contains the randomly generated position.
|
||||
* @param MinDistanceToSurface The minimum distance between the generated position and the closest surface/volume.
|
||||
* @param AvoidVolumes If true then the position will not be inside a volume and min distance away from it.
|
||||
* @return Return true if success otherwise false. If this fails it can be because the min distance to surface is too large.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool GenerateRandomPositionInRoom(FVector& OutPosition, float MinDistanceToSurface = 0.0f, bool AvoidVolumes = false);
|
||||
|
||||
/**
|
||||
* Generate a uniform random position within the room from a random stream.
|
||||
* @param OutPosition Contains the randomly generated position.
|
||||
* @param RandomStream A random generator used to generate the position on the plane.
|
||||
* @param MinDistanceToSurface The minimum distance between the generated position and the closest surface/volume.
|
||||
* @param AvoidVolumes If true then the position will not be inside a volume and min distance away from it.
|
||||
* @return Return true if success otherwise false. If this fails it can be because the min distance to surface is too large.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool GenerateRandomPositionInRoomFromStream(FVector& OutPosition, const FRandomStream& RandomStream, float MinDistanceToSurface = 0.0f, bool AvoidVolumes = false);
|
||||
|
||||
/**
|
||||
* Generates a random position on the surface of a given spawn location, while ensuring that the generated position is at least `MinDistanceToEdge` away from any edges. The `LabelFilter` parameter allows you to specify which types of surfaces should be considered for generating the random position.
|
||||
*
|
||||
* @param SpawnLocation The location where the random position should be generated.
|
||||
* @param MinDistanceToEdge The minimum distance from the edge that the generated position must have.
|
||||
* @param LabelFilter A filter that specifies which types of surfaces should be considered for generating the random position.
|
||||
* @param OutPosition The generated position.
|
||||
* @param OutNormal The normal vector of the generated position.
|
||||
* @return A boolean value indicating whether a valid position was found. If no valid position could be found, both `OutPosition` and `OutNormal` will be set to zero vectors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool GenerateRandomPositionOnSurface(EMRUKSpawnLocation SpawnLocation, float MinDistanceToEdge, FMRUKLabelFilter LabelFilter, FVector& OutPosition, FVector& OutNormal);
|
||||
|
||||
/**
|
||||
* Cast a ray and return the closest hit anchor
|
||||
* @param Origin Origin The origin of the ray.
|
||||
* @param Direction Direction The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param OutHit The closest hit.
|
||||
* @return The anchor that the ray hit.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
AMRUKAnchor* Raycast(const FVector& Origin, const FVector& Direction, float MaxDist, const FMRUKLabelFilter& LabelFilter, FMRUKHit& OutHit);
|
||||
|
||||
/**
|
||||
* Cast a ray and collect hits against the volume and plane bounds in this room. The order of the hits in the array is not specified.
|
||||
* @param Origin Origin The origin of the ray.
|
||||
* @param Direction Direction The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param OutHits The hits the ray collected.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param OutAnchors The anchors that were hit. Each anchor in this array corresponds to a entry at the same position in OutHits.
|
||||
* @return Whether the ray hit anything
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
bool RaycastAll(const FVector& Origin, const FVector& Direction, float MaxDist, const FMRUKLabelFilter& LabelFilter, TArray<FMRUKHit>& OutHits, TArray<AMRUKAnchor*>& OutAnchors);
|
||||
|
||||
/**
|
||||
* Clear all anchors from the room.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void ClearRoom();
|
||||
|
||||
/**
|
||||
* Check if the room does have any of the labels.
|
||||
* @param Labels The labels to check.
|
||||
* @return Whether the label was found in the room.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool DoesRoomHave(const TArray<FString>& Labels);
|
||||
|
||||
/**
|
||||
* Get the position on the surface that is closest to the given position with respect to the distance.
|
||||
* @param WorldPosition The position in world space from which the closest surface point should be found.
|
||||
* @param OutSurfacePosition The closest position on the closest surface if any. Otherwise zero.
|
||||
* @param OutSurfaceDistance The distance between WorldPosition and OutSurfacePosition.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param MaxDistance The distance to which a closest surface position should be searched. Everything below or equal to zero will be treated as infinity.
|
||||
* @return The Anchor on which the closest surface position was found or a null pointer otherwise.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
AMRUKAnchor* TryGetClosestSurfacePosition(const FVector& WorldPosition, FVector& OutSurfacePosition, double& OutSurfaceDistance, const FMRUKLabelFilter& LabelFilter, double MaxDistance = 0.0);
|
||||
|
||||
/**
|
||||
* Checks if the given position is on or inside of any scene volume in the room.
|
||||
* Floor, ceiling and wall anchors will be excluded from the search.
|
||||
* @param WorldPosition The position in world space to check
|
||||
* @param TestVerticalBounds Whether the vertical bounds should be checked or not
|
||||
* @param Tolerance Tolerance
|
||||
* @return The anchor the WorldPosition is in. A null pointer otherwise.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* IsPositionInSceneVolume(const FVector& WorldPosition, bool TestVerticalBounds = true, double Tolerance = 0.0);
|
||||
|
||||
/**
|
||||
* Finds the closest seat given a ray.
|
||||
* @param RayOrigin The origin of the ray.
|
||||
* @param RayDirection The direction of the ray.
|
||||
* @param OutSeatTransform The seat pose.
|
||||
* @return If any seat was found the Anchor that has seats available will be returned. Otherwise a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* TryGetClosestSeatPose(const FVector& RayOrigin, const FVector& RayDirection, FTransform& OutSeatTransform);
|
||||
|
||||
/**
|
||||
* Finds all anchors in this room that have the given label attached.
|
||||
* @param Label The label to search for.
|
||||
* @return An array off anchors with the given label.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
TArray<AMRUKAnchor*> GetAnchorsByLabel(const FString& Label) const;
|
||||
|
||||
/**
|
||||
* Finds the first anchor in this room that has the given label attached.
|
||||
* @param Label The label to search for.
|
||||
* @return If found, the Anchor that has the label attached. Otherwise a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* GetFirstAnchorByLabel(const FString& Label) const;
|
||||
|
||||
/**
|
||||
* Get a suggested pose (position & rotation) from a raycast to place objects on surfaces in the scene.
|
||||
* There are different positioning modes available. Default just uses the position where the raycast
|
||||
* hit the object. Edge snaps the position to the edge that is nearest to the user and Center simply
|
||||
* centers the position on top of the surface.
|
||||
* @param RayOrigin The origin of the ray.
|
||||
* @param RayDirection The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param OutPose The calculated pose.
|
||||
* @param PositioningMethod The method that should be used for determining the position on the surface.
|
||||
* @return The anchor that was hit by the ray if any. Otherwise a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
AMRUKAnchor* GetBestPoseFromRaycast(const FVector& RayOrigin, const FVector& RayDirection, double MaxDist, const FMRUKLabelFilter& LabelFilter, FTransform& OutPose, EMRUKPositioningMethod PositioningMethod = EMRUKPositioningMethod::Default);
|
||||
|
||||
/**
|
||||
* Return the longest wall in the room that has no other walls behind it.
|
||||
* @param Tolerance The tolerance to use when determining wall that are behind.
|
||||
* @return The wall anchor that is the key wall in the room.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* GetKeyWall(double Tolerance = 0.1);
|
||||
|
||||
/**
|
||||
* Return the largest surface for a given label.
|
||||
* @param Label The label of the surfaces to search in.
|
||||
* @return The anchor that has the largest surface if any. Otherwise, a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* GetLargestSurface(const FString& Label);
|
||||
|
||||
/**
|
||||
* Attach a procedural mesh to the walls. This is done at the room level to ensure the UV coordinates
|
||||
* can be done in a seamless way if desired.
|
||||
* @param WallTextureCoordinateModes Mode of the wall texture coordinates.
|
||||
* @param CutHoleLabels Labels for which holes should be cut into the plane meshes
|
||||
* @param ProceduralMaterial Material to apply on top of the procedural mesh.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "WallTextureCoordinateModes", DeprecatedFunction, DeprecationMessage = "Use GenerateProceduralMesh instead."))
|
||||
void AttachProceduralMeshToWalls(const TArray<FMRUKTexCoordModes>& WallTextureCoordinateModes, const TArray<FString>& CutHoleLabels, UMaterialInterface* ProceduralMaterial = nullptr);
|
||||
|
||||
/**
|
||||
* Spawn meshes on the position of the anchors of the room.
|
||||
* The actors should have Z as up Y as right and X as forward.
|
||||
* The pivot point should be in the bottom center.
|
||||
* @param SpawnGroups A map which tells to spawn which actor to a given label.
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes.
|
||||
* @param ProceduralMaterial Material to apply on top of the procedural mesh if any.
|
||||
* @param ShouldFallbackToProcedural Whether or not it should by default fallback to generating a procedural mesh if no actor class has been specified for a label.
|
||||
* @return All spawned interior actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "Use AMRUKAnchorActorSpawner instead."), Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnInterior(const TMap<FString, FMRUKSpawnGroup>& SpawnGroups, const TArray<FString>& CutHoleLabels, UMaterialInterface* ProceduralMaterial = nullptr, bool ShouldFallbackToProcedural = true);
|
||||
|
||||
/**
|
||||
* Spawn meshes on the position of the anchors of the room from a random stream.
|
||||
* The actors should have Z as up Y as right and X as forward.
|
||||
* The pivot point should be in the bottom center.
|
||||
* @param SpawnGroups A map wich tells to spawn which actor to a given label.
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes.
|
||||
* @param RandomStream A random generator to choose randomly between actor classes if there a multiple for one label.
|
||||
* @param ProceduralMaterial Material to apply on top of the procedural mesh if any.
|
||||
* @param ShouldFallbackToProcedural Whether or not it should by default fallback to generating a procedural mesh if no actor class has been specified for a label.
|
||||
* @return All spawned interior actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "Use AMRUKAnchorActorSpawner instead."), Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnInteriorFromStream(const TMap<FString, FMRUKSpawnGroup>& SpawnGroups, const FRandomStream& RandomStream, const TArray<FString>& CutHoleLabels, UMaterialInterface* ProceduralMaterial = nullptr, bool ShouldFallbackToProcedural = true);
|
||||
|
||||
/**
|
||||
* Check if the given anchor is a wall anchor.
|
||||
* @param Anchor The anchor to check.
|
||||
* @return Whether the anchor is a wall anchor or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool IsWallAnchor(AMRUKAnchor* Anchor) const;
|
||||
|
||||
/**
|
||||
* Compute the wall mesh texture coordinate adjustments that are needed to generate proper texture coordinates for the walls.
|
||||
* @param WallTextureCoordinateModes The texture coordinate mode to use for the walls.
|
||||
* @param OutAnchorsWithPlaneUVs The computed texture coordinate adjustment with the wall anchor.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void ComputeWallMeshUVAdjustments(const TArray<FMRUKTexCoordModes>& WallTextureCoordinateModes, TArray<FMRUKAnchorWithPlaneUVs>& OutAnchorsWithPlaneUVs);
|
||||
|
||||
/**
|
||||
* Load the triangle mesh of the global mesh anchor if it's available.
|
||||
* @param Material The Material to show if the global mesh is visible.
|
||||
* @return On success true, otherwise false.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool LoadGlobalMeshFromDevice(UMaterialInterface* Material = nullptr);
|
||||
|
||||
/**
|
||||
* Load the triangle mesh of the global mesh anchor. For this function to succeed you need to make
|
||||
* sure to have a global mesh specified in the JSON file. Not every JSON file has a global mesh in it.
|
||||
* @param JsonString The string with the JSON data.
|
||||
* @param Material Material to apply on the global mesh.
|
||||
* @return On Success true, otherwise false.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool LoadGlobalMeshFromJsonString(const FString& JsonString, UMaterialInterface* Material = nullptr);
|
||||
|
||||
/**
|
||||
* Compute the centroid of the room by taking the points of the floor boundary.
|
||||
* The centroid may be outside of the room for non convex rooms.
|
||||
* The Z value determines the height of the resulting vectors and ranges from
|
||||
* 0 to 1. A Z value of 1 corresponds to the ceiling positions Z, while a Z value
|
||||
* of 0 corresponds to the floor positions Z. Any value between 0 and 1 will
|
||||
* interpolate between the two values.
|
||||
* In case the floor and ceiling anchors haven't been loaded yet a zero vector
|
||||
* will be returned.
|
||||
* @param Z Value used for interpolation of Z.
|
||||
* @return The centroid.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
FVector ComputeCentroid(double Z = 0.5);
|
||||
|
||||
public:
|
||||
AMRUKRoom(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
void EndPlay(EEndPlayReason::Type Reason) override;
|
||||
|
||||
void LoadFromData(UMRUKRoomData* RoomData);
|
||||
|
||||
void AttachProceduralMeshToWalls(const TArray<FString>& CutHoleLabels, UMaterialInterface* ProceduralMaterial = nullptr);
|
||||
void UpdateWorldLock(APawn* Pawn, const FVector& HeadWorldPosition) const;
|
||||
|
||||
TSharedRef<FJsonObject> JsonSerialize();
|
||||
|
||||
bool Corresponds(UMRUKRoomData* RoomQuery) const;
|
||||
|
||||
private:
|
||||
friend class FMRUKSpec;
|
||||
|
||||
AMRUKAnchor* SpawnAnchor();
|
||||
|
||||
void InitializeRoom();
|
||||
void ComputeRoomBounds();
|
||||
void ComputeAnchorHierarchy();
|
||||
void ComputeSeats();
|
||||
void ComputeRoomEdges();
|
||||
|
||||
UFUNCTION(CallInEditor)
|
||||
void AddAnchorToRoom(AMRUKAnchor* Anchor);
|
||||
|
||||
class UProceduralMeshComponent* GetOrCreateGlobalMeshProceduralMeshComponent(bool& OutExistedAlready) const;
|
||||
void SetupGlobalMeshProceduralMeshComponent(UProceduralMeshComponent& ProcMeshComponent, bool ExistedAlready, UMaterialInterface* Material) const;
|
||||
|
||||
/**
|
||||
* Get the list of walls in an order such that each one wall shares an edge with the next
|
||||
* one in the list.
|
||||
*/
|
||||
TArray<TObjectPtr<AMRUKAnchor>> ComputeConnectedWalls() const;
|
||||
|
||||
FOculusXRRoomLayout RoomLayout;
|
||||
UPROPERTY()
|
||||
AMRUKAnchor* KeyWallAnchor = nullptr;
|
||||
|
||||
struct Surface
|
||||
{
|
||||
AMRUKAnchor* Anchor;
|
||||
float UsableArea;
|
||||
bool IsPlane;
|
||||
FBox2D Bounds;
|
||||
EMRUKBoxSide Side;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Engine/DataTable.h"
|
||||
#include "MRUtilityKitSceneDataProvider.generated.h"
|
||||
|
||||
UCLASS(ClassGroup = MRUtilityKit, meta = (DisplayName = "MR Utility Kit Scene Data Provider"))
|
||||
/*
|
||||
* This actor is used to provide scene data to the MR Utility Kit when running in editor.
|
||||
* You can also use it to not load a room from device.
|
||||
* Use RandomRoom to load a random room from the list of rooms.
|
||||
*/
|
||||
class MRUTILITYKIT_API AMRUKSceneDataProvider : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/*
|
||||
* This list holds the rooms that can be loaded, the key is the room type and the value is a data table that contains multiple rooms.
|
||||
* Roomtypes such as Bedrooms, Livingrooms, etc.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, Category = "MR Utility Kit")
|
||||
TMap<FString, UDataTable*> Rooms;
|
||||
|
||||
/*
|
||||
* When this is true, a random room will be loaded from the list of rooms.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MR Utility Kit")
|
||||
bool bUseRandomRoom = true;
|
||||
|
||||
/*
|
||||
* When this is true, a random room will be loaded a specific room class, defined in Rooms (Bedrooms, Offices, ..).
|
||||
*/
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MR Utility Kit", meta = (EditCondition = "!bUseRandomRoom", EditConditionHides))
|
||||
bool bUseRandomRoomFromClass = false;
|
||||
|
||||
/*
|
||||
* Use this property to define a specific room class to load, only visible when bUseRandomRoomFromClass is true.
|
||||
* This can be a room class such as Bedrooms, Offices, ..
|
||||
*/
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MR Utility Kit", meta = (EditCondition = "bUseRandomRoomFromClass && !bUseRandomRoom", EditConditionHides))
|
||||
FString SpecificRoomClass;
|
||||
|
||||
/*
|
||||
* Define a specific room to load, only visible when bUseRandomRoom is false.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MR Utility Kit", meta = (EditCondition = "!bUseRandomRoom && !bUseRandomRoomFromClass", EditConditionHides))
|
||||
FString SpecificRoomName;
|
||||
|
||||
/*
|
||||
* Gets you a room from the list of rooms, if bUseRandomRoom is true, a random room will be returned.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void GetRoom(FString& RoomJSON, FString& RoomName);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
};
|
||||
|
||||
USTRUCT(Blueprintable, BlueprintType)
|
||||
struct FJSONData : public FTableRowBase
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MR Utility Kit")
|
||||
FString JSON;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "MRUtilityKitSeatsComponent.generated.h"
|
||||
|
||||
/**
|
||||
* This component gets attached to Anchors which have seats available.
|
||||
* Seats can be used for example to spawn avatars in the correct locations.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit)
|
||||
class MRUTILITYKIT_API UMRUKSeatsComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<FTransform> SeatPoses;
|
||||
|
||||
/**
|
||||
* Calculate the seats poses that are available on the actor.
|
||||
* This gets called automatically after the room has been loaded.
|
||||
* However, it's okay to call this function again with a different SeatWidth.
|
||||
* The seat poses will then get recalculated.
|
||||
* @param SeatWidth The width of each seat.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void CalculateSeatPoses(double SeatWidth = 60.0);
|
||||
};
|
||||
@@ -0,0 +1,204 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "OculusXRAnchorTypes.h"
|
||||
#include "OculusXRRoomLayoutManagerComponent.h"
|
||||
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const FString& String);
|
||||
|
||||
void MRUKDeserialize(const FJsonValue& Value, FString& String);
|
||||
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const FOculusXRUUID& UUID);
|
||||
|
||||
void MRUKDeserialize(const FJsonValue& Value, FOculusXRUUID& UUID);
|
||||
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const double& Number);
|
||||
|
||||
void MRUKDeserialize(const FJsonValue& Value, double& Number);
|
||||
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const FOculusXRRoomLayout& RoomLayout);
|
||||
|
||||
void MRUKDeserialize(const FJsonValue& Value, FOculusXRRoomLayout& RoomLayout);
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const UE::Math::TVector2<T>& Vector)
|
||||
{
|
||||
return MakeShareable(new FJsonValueArray({ MakeShareable(new FJsonValueNumber(Vector.X)), MakeShareable(new FJsonValueNumber(Vector.Y)) }));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, UE::Math::TVector2<T>& Vector)
|
||||
{
|
||||
if (auto Array = Value.AsArray(); Array.Num() == 2)
|
||||
{
|
||||
MRUKDeserialize(*Array[0], Vector.X);
|
||||
MRUKDeserialize(*Array[1], Vector.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogJson, Error, TEXT("Json Array is of length %d (expected 2) when deserializing TVector2"), Array.Num());
|
||||
Vector = UE::Math::TVector2<T>::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const UE::Math::TVector<T>& Vector)
|
||||
{
|
||||
return MakeShareable(new FJsonValueArray({ MakeShareable(new FJsonValueNumber(Vector.X)), MakeShareable(new FJsonValueNumber(Vector.Y)), MakeShareable(new FJsonValueNumber(Vector.Z)) }));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, UE::Math::TVector<T>& Vector)
|
||||
{
|
||||
auto Array = Value.AsArray();
|
||||
if (Array.Num() == 3)
|
||||
{
|
||||
MRUKDeserialize(*Array[0], Vector.X);
|
||||
MRUKDeserialize(*Array[1], Vector.Y);
|
||||
MRUKDeserialize(*Array[2], Vector.Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogJson, Error, TEXT("Json Array is of length %d (expected 3) when deserializing TVector"), Array.Num());
|
||||
Vector = UE::Math::TVector<T>::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const UE::Math::TRotator<T>& Rotation)
|
||||
{
|
||||
return MakeShareable(new FJsonValueArray({ MakeShareable(new FJsonValueNumber(Rotation.Pitch)), MakeShareable(new FJsonValueNumber(Rotation.Yaw)), MakeShareable(new FJsonValueNumber(Rotation.Roll)) }));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, UE::Math::TRotator<T>& Rotation)
|
||||
{
|
||||
auto Array = Value.AsArray();
|
||||
if (Array.Num() == 3)
|
||||
{
|
||||
MRUKDeserialize(*Array[0], Rotation.Pitch);
|
||||
MRUKDeserialize(*Array[1], Rotation.Yaw);
|
||||
MRUKDeserialize(*Array[2], Rotation.Roll);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogJson, Error, TEXT("Json Array is of length %d (expected 3) when deserializing TRotator"), Array.Num());
|
||||
Rotation = UE::Math::TRotator<T>::ZeroRotator;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const UE::Math::TBox2<T>& Box)
|
||||
{
|
||||
if (Box.bIsValid)
|
||||
{
|
||||
const TSharedRef<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||
JsonObject->SetField(TEXT("Min"), MRUKSerialize(Box.Min));
|
||||
JsonObject->SetField(TEXT("Max"), MRUKSerialize(Box.Max));
|
||||
return MakeShareable(new FJsonValueObject(JsonObject));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeShareable(new FJsonValueNull());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, UE::Math::TBox2<T>& Box)
|
||||
{
|
||||
if (Value.IsNull())
|
||||
{
|
||||
Box.Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto Object = Value.AsObject();
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Min")), Box.Min);
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Max")), Box.Max);
|
||||
Box.bIsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const UE::Math::TBox<T>& Box)
|
||||
{
|
||||
if (Box.IsValid)
|
||||
{
|
||||
const TSharedRef<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||
JsonObject->SetField(TEXT("Min"), MRUKSerialize(Box.Min));
|
||||
JsonObject->SetField(TEXT("Max"), MRUKSerialize(Box.Max));
|
||||
return MakeShareable(new FJsonValueObject(JsonObject));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeShareable(new FJsonValueNull());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, UE::Math::TBox<T>& Box)
|
||||
{
|
||||
if (Value.IsNull())
|
||||
{
|
||||
Box.Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto Object = Value.AsObject();
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Min")), Box.Min);
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Max")), Box.Max);
|
||||
Box.IsValid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const UE::Math::TTransform<T>& Transform)
|
||||
{
|
||||
const TSharedRef<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||
JsonObject->SetField(TEXT("Translation"), MRUKSerialize(Transform.GetTranslation()));
|
||||
JsonObject->SetField(TEXT("Rotation"), MRUKSerialize(Transform.Rotator()));
|
||||
JsonObject->SetField(TEXT("Scale"), MRUKSerialize(Transform.GetScale3D()));
|
||||
return MakeShareable(new FJsonValueObject(JsonObject));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, UE::Math::TTransform<T>& Transform)
|
||||
{
|
||||
const auto Object = Value.AsObject();
|
||||
UE::Math::TVector<T> Translation;
|
||||
UE::Math::TRotator<T> Rotation;
|
||||
UE::Math::TVector<T> Scale;
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Translation")), Translation);
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Rotation")), Rotation);
|
||||
MRUKDeserialize(*Object->GetField<EJson::None>(TEXT("Scale")), Scale);
|
||||
|
||||
Transform.SetComponents(UE::Math::TQuat<T>(Rotation), Translation, Scale);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TSharedPtr<FJsonValue> MRUKSerialize(const TArray<T>& Array)
|
||||
{
|
||||
TArray<TSharedPtr<FJsonValue>> JsonArray;
|
||||
JsonArray.Reserve(Array.Num());
|
||||
for (const auto& Item : Array)
|
||||
{
|
||||
JsonArray.Add(MRUKSerialize(Item));
|
||||
}
|
||||
return MakeShareable(new FJsonValueArray(JsonArray));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MRUKDeserialize(const FJsonValue& Value, TArray<T>& OutArray)
|
||||
{
|
||||
auto Array = Value.AsArray();
|
||||
OutArray.Empty();
|
||||
OutArray.Reserve(Array.Num());
|
||||
for (const auto& Item : Array)
|
||||
{
|
||||
T ItemDeserialized;
|
||||
MRUKDeserialize(*Item, ItemDeserialized);
|
||||
OutArray.Push(ItemDeserialized);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Dom/JsonObject.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "GameFramework/WorldSettings.h"
|
||||
#include "MRUtilityKitRoom.h"
|
||||
#include "MRUtilityKit.h"
|
||||
#include "MRUtilityKitData.h"
|
||||
#include "OculusXRAnchorsRequests.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "Tickable.h"
|
||||
|
||||
#include "MRUtilityKitSubsystem.generated.h"
|
||||
|
||||
/**
|
||||
* The Mixed Reality Utility Kit subsystem.
|
||||
*
|
||||
* This subsystem acts as a container for scene/anchor data. It has methods to load
|
||||
* the scene data from the device or a JSON file. After the scene data has been loaded
|
||||
* it will be stored inside the subsystem to make it possible to query the data from
|
||||
* everywhere. In addition, it offers methods to fulfill queries on the scene data
|
||||
* like ray casts or simple content placement.
|
||||
*
|
||||
* The subsystem only contains core functionality that is useful for most cases.
|
||||
* More specific functionality is part of actors. For example, if your goal is to spawn
|
||||
* meshes in the place of scene anchors you can place the AMRUKAnchorActorSpawner in the
|
||||
* level to do this. When a level loads you would first load the anchor data from the
|
||||
* device with this subsystem by calling LoadSceneFromDevice() and then the AMRUKAnchorActorSpawner
|
||||
* will listen for the subsystem to load the scene data and then spawn the actors accordingly.
|
||||
*
|
||||
* You can expect methods in this subsystem to take all loaded rooms into consideration when computing.
|
||||
* If you want to use a method only on a single specific room, there is most of the time a method
|
||||
* with the same name on the AMRUKRoom.
|
||||
*/
|
||||
UCLASS(ClassGroup = MRUtilityKit)
|
||||
class MRUTILITYKIT_API UMRUKSubsystem : public UGameInstanceSubsystem, public FTickableGameObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLoaded, bool, Success);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCaptureComplete, bool, Success);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRoomCreated, AMRUKRoom*, Room);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRoomUpdated, AMRUKRoom*, Room);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRoomRemoved, AMRUKRoom*, Room);
|
||||
|
||||
/**
|
||||
* The status of the scene loading. When loading from device this is an asynchronous process
|
||||
* so will be in the Busy state until it moves to Complete or Failed.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
EMRUKInitStatus SceneLoadStatus = EMRUKInitStatus::None;
|
||||
|
||||
/**
|
||||
* An event that will trigger when a scene is loaded either from Device or from JSON.
|
||||
* The Success parameter indicates whether the scene was loaded successfully or not.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnLoaded OnSceneLoaded;
|
||||
|
||||
/**
|
||||
* An event that gets fired after a room has been created.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnRoomCreated OnRoomCreated;
|
||||
|
||||
/**
|
||||
* An event that gets fired after a room has been updated.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnRoomUpdated OnRoomUpdated;
|
||||
|
||||
/**
|
||||
* An event that gets fired when a room gets removed.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnRoomRemoved OnRoomRemoved;
|
||||
|
||||
/**
|
||||
* An event that will trigger when the capture flow completed.
|
||||
* The Success parameter indicates whether the scene was captured successfully or not.
|
||||
*/
|
||||
UPROPERTY(BlueprintAssignable, Category = "MR Utility Kit")
|
||||
FOnCaptureComplete OnCaptureComplete;
|
||||
|
||||
/**
|
||||
* Contains a list of rooms that are tracked by the mixed reality utility kit subsystem.
|
||||
*/
|
||||
UPROPERTY(VisibleInstanceOnly, Transient, BlueprintReadOnly, Category = "MR Utility Kit")
|
||||
TArray<TObjectPtr<AMRUKRoom>> Rooms;
|
||||
|
||||
/**
|
||||
* When world locking is enabled the position of the VR Pawn will be adjusted each frame to ensure
|
||||
* the room anchors are where they should be relative to the camera position. This is necessary to
|
||||
* ensure the position of the virtual objects in the world do not get out of sync with the real world.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MR Utility Kit")
|
||||
bool EnableWorldLock = true;
|
||||
|
||||
|
||||
/**
|
||||
* Cast a ray and return the closest hit anchor in the scene.
|
||||
* @param Origin Origin The origin of the ray.
|
||||
* @param Direction Direction The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param OutHit The closest hit.
|
||||
* @return The anchor that the ray hit
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
AMRUKAnchor* Raycast(const FVector& Origin, const FVector& Direction, float MaxDist, const FMRUKLabelFilter& LabelFilter, FMRUKHit& OutHit);
|
||||
|
||||
/**
|
||||
* Cast a ray and collect hits against the volumes and plane bounds in every room in the scene.
|
||||
* The order of the hits in the array is not specified.
|
||||
* @param Origin Origin The origin of the ray.
|
||||
* @param Direction Direction The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param OutHits The hits the ray collected.
|
||||
* @param OutAnchors The anchors that were hit. Each anchor in this array corresponds to a entry at the same position in OutHits.
|
||||
* @return Whether the ray hit anything
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
bool RaycastAll(const FVector& Origin, const FVector& Direction, float MaxDist, const FMRUKLabelFilter& LabelFilter, TArray<FMRUKHit>& OutHits, TArray<AMRUKAnchor*>& OutAnchors);
|
||||
|
||||
/**
|
||||
* Return the room that the headset is currently in. If the headset is not in any given room
|
||||
* then it will return the room the headset was last in when this function was called.
|
||||
* If the headset hasn't been in a valid room yet then return the first room in the list.
|
||||
* If no rooms have been loaded yet then return null.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKRoom* GetCurrentRoom() const;
|
||||
|
||||
/**
|
||||
* Save all rooms and anchors to JSON. This JSON representation can than later be used by
|
||||
* LoadSceneFromJsonString() to load the scene again.
|
||||
* @return the JSON string.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
FString SaveSceneToJsonString();
|
||||
|
||||
/**
|
||||
* Load rooms and anchors from a JSON representation.
|
||||
* If the scene is already loaded the scene will be updated with the changes.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void LoadSceneFromJsonString(const FString& String);
|
||||
|
||||
/**
|
||||
* Load rooms and anchors from the device.
|
||||
* If the scene is already loaded the scene will be updated with the changes.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void LoadSceneFromDevice();
|
||||
|
||||
|
||||
/**
|
||||
* Removes and clears every room.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
void ClearScene();
|
||||
|
||||
/**
|
||||
* Get the position on the surface that is closest to the given position with respect to the distance in all rooms.
|
||||
* @param WorldPosition The position in world space from which the closest surface point should be found.
|
||||
* @param OutSurfacePosition The closest position on the closest surface if any. Otherwise zero.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param MaxDistance The distance to which a closest surface position should be searched. Everything below or equal to zero will be treated as infinity.
|
||||
* @return The Anchor on which the closest surface position was found or a null pointer otherwise.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
AMRUKAnchor* TryGetClosestSurfacePosition(const FVector& WorldPosition, FVector& OutSurfacePosition, const FMRUKLabelFilter& LabelFilter, double MaxDistance = 0.0);
|
||||
|
||||
/**
|
||||
* Finds the closest seat given a ray.
|
||||
* @param RayOrigin The origin of the ray.
|
||||
* @param RayDirection The direction of the ray.
|
||||
* @param OutSeatTransform The seat pose.
|
||||
* @return If any seat was found the Anchor that has seats available will be returned. Otherwise a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* TryGetClosestSeatPose(const FVector& RayOrigin, const FVector& RayDirection, FTransform& OutSeatTransform);
|
||||
|
||||
/**
|
||||
* Get a suggested pose (position & rotation) from a raycast to place objects on surfaces in the scene.
|
||||
* There are different positioning modes available. Default just uses the position where the raycast
|
||||
* hit the object. Edge snaps the position to the edge that is nearest to the user and Center simply
|
||||
* centers the position on top of the surface.
|
||||
* @param RayOrigin The origin of the ray.
|
||||
* @param RayDirection The direction of the ray.
|
||||
* @param MaxDist The maximum distance the ray should travel.
|
||||
* @param LabelFilter The label filter can be used to include/exclude certain labels from the search.
|
||||
* @param OutPose The calculated pose.
|
||||
* @param PositioningMethod The method that should be used for determining the position on the surface.
|
||||
* @return The anchor that was hit by the ray if any. Otherwise a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit", meta = (AutoCreateRefTerm = "LabelFilter"))
|
||||
AMRUKAnchor* GetBestPoseFromRaycast(const FVector& RayOrigin, const FVector& RayDirection, double MaxDist, const FMRUKLabelFilter& LabelFilter, FTransform& OutPose, EMRUKPositioningMethod PositioningMethod = EMRUKPositioningMethod::Default);
|
||||
|
||||
/**
|
||||
* Return the longest wall in the current room that has no other walls behind it.
|
||||
* @param Tolerance The tolerance to use when determining wall that are behind.
|
||||
* @return The wall anchor that is the key wall in the room.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* GetKeyWall(double Tolerance = 0.1);
|
||||
|
||||
/**
|
||||
* Return the largest surface for a given label in the current room.
|
||||
* @param Label The label of the surfaces to search in.
|
||||
* @return The anchor that has the largest surface if any. Otherwise, a null pointer.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* GetLargestSurface(const FString& Label);
|
||||
|
||||
/**
|
||||
* Checks if the given position is on or inside of any scene volume in the rooms.
|
||||
* All rooms will be checked and the first anchors scene volume that has the point on or inside it will be returned.
|
||||
* @param WorldPosition The position in world space to check
|
||||
* @param TestVerticalBounds Whether the vertical bounds should be checked or not
|
||||
* @param Tolerance Tolerance
|
||||
* @return The anchor the WorldPosition is in. A null pointer otherwise.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
AMRUKAnchor* IsPositionInSceneVolume(const FVector& WorldPosition, bool TestVerticalBounds = true, double Tolerance = 0.0);
|
||||
|
||||
/**
|
||||
* Spawn meshes on the position of the anchors of each room.
|
||||
* The actors should have Z as up Y as right and X as forward.
|
||||
* The pivot point should be in the bottom center.
|
||||
* @param SpawnGroups A map which tells to spawn which actor to a given label.
|
||||
* @param ProceduralMaterial Material to apply on top of the procedural mesh if any.
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes.
|
||||
* @param ShouldFallbackToProcedural Whether or not it should by default fallback to generating a procedural mesh if no actor class has been specified for a label.
|
||||
* @return The spawned actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "Use AMRUKAnchorActorSpawner instead."), Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnInterior(const TMap<FString, FMRUKSpawnGroup>& SpawnGroups, const TArray<FString>& CutHoleLabels, UMaterialInterface* ProceduralMaterial = nullptr, bool ShouldFallbackToProcedural = true);
|
||||
|
||||
/**
|
||||
* Spawn meshes on the position of the anchors of each room from a random stream.
|
||||
* The actors should have Z as up Y as right and X as forward.
|
||||
* The pivot point should be in the bottom center.
|
||||
* @param SpawnGroups A map which tells to spawn which actor to a given label.
|
||||
* @param RandomStream A random generator to choose randomly between actor classes if there a multiple for one label.
|
||||
* @param CutHoleLabels Labels for which the generated mesh should have holes. Only works with planes.
|
||||
* @param ProceduralMaterial Material to apply on top of the procedural mesh if any.
|
||||
* @param ShouldFallbackToProcedural Whether or not it should by default fallback to generating a procedural mesh if no actor class has been specified for a label.
|
||||
* @return The spawned actors.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "Use AMRUKAnchorActorSpawner instead."), Category = "MR Utility Kit")
|
||||
TArray<AActor*> SpawnInteriorFromStream(const TMap<FString, FMRUKSpawnGroup>& SpawnGroups, const FRandomStream& RandomStream, const TArray<FString>& CutHoleLabels, UMaterialInterface* ProceduralMaterial = nullptr, bool ShouldFallbackToProcedural = true);
|
||||
|
||||
/**
|
||||
* Launch the scene capture. After a successful capture the scene should be updated.
|
||||
* @return Whether the capture was successful.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "MR Utility Kit")
|
||||
bool LaunchSceneCapture();
|
||||
|
||||
public:
|
||||
void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
void Deinitialize() override;
|
||||
|
||||
TSharedRef<FJsonObject> JsonSerialize();
|
||||
void UnregisterRoom(AMRUKRoom* Room);
|
||||
// Calculate the bounds of an Actor class and return it, the result is saved in a cache for faster lookup.
|
||||
FBox GetActorClassBounds(TSubclassOf<AActor> Actor);
|
||||
UOculusXRRoomLayoutManagerComponent* GetRoomLayoutManager();
|
||||
|
||||
private:
|
||||
AMRUKRoom* SpawnRoom();
|
||||
|
||||
void FinishedLoading(bool Success);
|
||||
|
||||
// FTickableGameObject interface
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
virtual bool IsTickable() const override;
|
||||
virtual ETickableTickType GetTickableTickType() const override { return (HasAnyFlags(RF_ClassDefaultObject) ? ETickableTickType::Never : ETickableTickType::Conditional); }
|
||||
virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(UMRUKSubsystem, STATGROUP_Tickables); }
|
||||
virtual UWorld* GetTickableGameObjectWorld() const override { return GetWorld(); }
|
||||
// ~FTickableGameObject interface
|
||||
|
||||
UFUNCTION()
|
||||
void SceneDataLoadedComplete(bool Success);
|
||||
UFUNCTION()
|
||||
void UpdatedSceneDataLoadedComplete(bool Success);
|
||||
UFUNCTION()
|
||||
void SceneCaptureComplete(FOculusXRUInt64 RequestId, bool bSuccess);
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UMRUKSceneData> SceneData = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
AActor* RoomLayoutManagerActor = nullptr;
|
||||
UPROPERTY()
|
||||
UOculusXRRoomLayoutManagerComponent* RoomLayoutManager = nullptr;
|
||||
UPROPERTY()
|
||||
mutable AMRUKRoom* CachedCurrentRoom = nullptr;
|
||||
mutable int64 CachedCurrentRoomFrame = 0;
|
||||
UPROPERTY()
|
||||
AActor* PositionGenerator = nullptr;
|
||||
|
||||
TMap<TSubclassOf<AActor>, FBox> ActorClassBoundsCache;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRTelemetry.h"
|
||||
|
||||
namespace MRUKTelemetry
|
||||
{
|
||||
using FLoadGuardianMarker = OculusXRTelemetry::TMarker<257237531>;
|
||||
using FLoadBlobShadowMarker = OculusXRTelemetry::TMarker<257244458>;
|
||||
using FLoadLightDispatcherMarker = OculusXRTelemetry::TMarker<257234454>;
|
||||
using FLoadDebugComponentMarker = OculusXRTelemetry::TMarker<257232584>;
|
||||
using FLoadAnchorActorSpawnerMarker = OculusXRTelemetry::TMarker<257232670>;
|
||||
using FLoadSceneFromDeviceMarker = OculusXRTelemetry::TMarker<257235234>;
|
||||
using FLoadSceneFromJsonMarker = OculusXRTelemetry::TMarker<257237876>;
|
||||
using FLoadGridSliceResizerMarker = OculusXRTelemetry::TMarker<257238248>;
|
||||
using FLoadDestructibleGlobalMeshSpawner = OculusXRTelemetry::TMarker<257232038>;
|
||||
} // namespace MRUKTelemetry
|
||||
Reference in New Issue
Block a user