Config for building for Quest

This commit is contained in:
2024-05-29 11:53:41 +03:00
parent 15cbcf8752
commit 0db31c34d1
353 changed files with 74095 additions and 3 deletions

View File

@@ -0,0 +1,38 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.IO;
namespace UnrealBuildTool.Rules
{
public class OculusXRPassthrough : ModuleRules
{
public OculusXRPassthrough(ReadOnlyTargetRules Target) : base(Target)
{
bUseUnity = true;
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"ProceduralMeshComponent",
"OculusXRHMD",
"OVRPluginXR",
"HeadMountedDisplay",
});
PublicIncludePaths.AddRange(new string[] {
"Runtime/Engine/Classes/Components",
"Runtime/Engine/Classes/Kismet",
});
PrivateIncludePaths.AddRange(new string[] {
// Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source
"OculusXRHMD/Private",
});
}
}
}

View File

@@ -0,0 +1,278 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRPassthroughColorLut.h"
#include "OculusXRPassthroughLayerComponent.h"
#include "OculusXRHMDPrivate.h"
#include "Math/UnrealMathUtility.h"
#include "GenericPlatform/GenericPlatformMath.h"
#include "UObject/ObjectSaveContext.h"
#include "OculusXRHMD.h"
#include "TextureResource.h"
namespace
{
ovrpPassthroughColorLutChannels ToOVRPColorLutChannels(EColorLutChannels InColorLutChannels)
{
switch (InColorLutChannels)
{
case ColorLutChannels_RGB:
return ovrpPassthroughColorLutChannels_Rgb;
case ColorLutChannels_RGBA:
return ovrpPassthroughColorLutChannels_Rgba;
default:
return ovrpPassthroughColorLutChannels_Invalid;
}
}
TArray<uint8> ColorArrayToColorData(const TArray<FColor>& InColorArray, bool IgnoreAlphaChannel)
{
TArray<uint8> Data;
const size_t ElementSize = IgnoreAlphaChannel ? 3 : 4;
Data.SetNum(InColorArray.Num() * ElementSize);
uint8* Dest = Data.GetData();
for (size_t i = 0; i < InColorArray.Num(); i++)
{
Data[i * ElementSize + 0] = InColorArray[i].R;
Data[i * ElementSize + 1] = InColorArray[i].G;
Data[i * ElementSize + 2] = InColorArray[i].B;
if (!IgnoreAlphaChannel)
{
Data[i * ElementSize + 3] = InColorArray[i].A;
}
}
return Data;
}
bool IsTextureDataValid(const FLutTextureData& Data)
{
return Data.Data.Num() > 0 && Data.Resolution > 0;
}
} // namespace
void UOculusXRPassthroughColorLut::SetLutFromArray(const TArray<FColor>& InColorArray, bool InIgnoreAlphaChannel)
{
const int32 Size = InColorArray.Num();
const int32 Resolution = FPlatformMath::RoundToInt(FPlatformMath::Pow(Size, 1.0 / 3));
if (Resolution > GetMaxResolution())
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Setting array ignored: Resoluton is exceeding maximum resoluton of %d."), GetMaxResolution());
return;
}
if (Resolution * Resolution * Resolution != Size)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Setting array ignored: Provided array size is not cube."));
return;
}
/* Check if size if power of 2 */
if ((Size & (Size - 1)) != 0)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Setting array ignored: Provided array does not result in a resolution that is a power of two."));
return;
}
ColorLutType = EColorLutType::Array;
const TArray<uint8>& Data = ColorArrayToColorData(InColorArray, InIgnoreAlphaChannel);
if (LutHandle == 0)
{
LutHandle = CreateLutObject(Data, Resolution);
return;
}
if (InIgnoreAlphaChannel == IgnoreAlphaChannel && Resolution == ColorArrayResolution)
{
UpdateLutObject(LutHandle, Data);
return;
}
DestroyLutObject(LutHandle);
LutHandle = CreateLutObject(Data, Resolution);
IgnoreAlphaChannel = InIgnoreAlphaChannel;
ColorArrayResolution = Resolution;
}
uint64 UOculusXRPassthroughColorLut::GetHandle()
{
if (LutHandle == 0 && ColorLutType == EColorLutType::TextureLUT && IsTextureDataValid(StoredTextureData))
{
LutHandle = CreateLutObject(StoredTextureData.Data, StoredTextureData.Resolution);
}
return LutHandle;
}
void UOculusXRPassthroughColorLut::PreSave(FObjectPreSaveContext ObjectSaveContext)
{
Super::PreSave(ObjectSaveContext);
#if WITH_EDITOR
StoredTextureData = TextureToColorData(LutTexture);
#endif
}
FLutTextureData UOculusXRPassthroughColorLut::TextureToColorData(class UTexture2D* InLutTexture) const
{
if (ColorLutType != EColorLutType::TextureLUT)
{
return FLutTextureData();
}
if (InLutTexture == nullptr)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Ignoring provided LUT texture. Provided texture is NULL."));
return FLutTextureData();
}
if (InLutTexture->LODGroup != TextureGroup::TEXTUREGROUP_ColorLookupTable)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Ignoring provided LUT texture. Provided texture is not LUT texture."));
return FLutTextureData();
}
if (InLutTexture->GetPlatformData()->Mips.Num() <= 0)
{
if (IsTextureDataValid(StoredTextureData))
{
// We do not need to save it again. Use previously saved data.
return StoredTextureData;
}
return FLutTextureData();
}
const uint32 TextureWidth = InLutTexture->GetImportedSize().X;
const uint32 TextureHeight = InLutTexture->GetImportedSize().Y;
uint32 ColorMapSize;
uint32 SlicesPerRow;
if (TextureWidth == TextureHeight)
{
float EdgeLength = FPlatformMath::Pow(TextureWidth, 2.0f / 3.0f);
ColorMapSize = FPlatformMath::RoundToInt(EdgeLength);
if (FPlatformMath::Abs(EdgeLength - ColorMapSize) > ZERO_ANIMWEIGHT_THRESH)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("LUT width and height are equal but don't correspond to an 'exploded cube'"));
return FLutTextureData();
}
SlicesPerRow = FPlatformMath::Sqrt(ColorMapSize * 1.0f);
}
else
{
if (TextureWidth != TextureHeight * TextureHeight)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("For rectangular LUTs, the width is expected to be equal to edgeLength^2"));
return FLutTextureData();
}
ColorMapSize = TextureHeight;
SlicesPerRow = TextureHeight;
}
FTexture2DMipMap& MipMap = InLutTexture->GetPlatformData()->Mips[0];
FByteBulkData* BulkData = &MipMap.BulkData;
const FColor* FormatedImageData = reinterpret_cast<const FColor*>(BulkData->Lock(LOCK_READ_ONLY));
TArray<FColor> Colors;
Colors.SetNum(ColorMapSize * ColorMapSize * ColorMapSize);
for (uint32 bi = 0; bi < ColorMapSize; bi++)
{
uint32 bi_row = bi % SlicesPerRow;
uint32 bi_col = bi / SlicesPerRow;
for (uint32 gi = 0; gi < ColorMapSize; gi++)
{
for (uint32 ri = 0; ri < ColorMapSize; ri++)
{
uint32 sX = ri + bi_row * ColorMapSize;
uint32 sY = gi + bi_col * ColorMapSize;
Colors[bi * ColorMapSize * ColorMapSize + gi * ColorMapSize + ri] = FormatedImageData[sX + sY * TextureWidth];
}
}
}
BulkData->Unlock();
return FLutTextureData(ColorArrayToColorData(Colors, IgnoreAlphaChannel), ColorMapSize);
}
uint64 UOculusXRPassthroughColorLut::CreateLutObject(const TArray<uint8>& InData, uint32 Resolution) const
{
ovrpPassthroughColorLutData OVRPData;
OVRPData.Buffer = InData.GetData();
OVRPData.BufferSize = InData.Num();
const EColorLutChannels Channels = IgnoreAlphaChannel ? EColorLutChannels::ColorLutChannels_RGB : EColorLutChannels::ColorLutChannels_RGBA;
ovrpPassthroughColorLut Handle;
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().CreatePassthroughColorLut(
ToOVRPColorLutChannels(Channels),
Resolution,
OVRPData,
&Handle)))
{
UE_LOG(LogTemp, Error, TEXT("Failed creating passthrough color lut."));
return 0;
}
return Handle;
}
void UOculusXRPassthroughColorLut::UpdateLutObject(uint64 Handle, const TArray<uint8>& InData) const
{
if (Handle == 0)
{
return;
}
ovrpPassthroughColorLutData OVRPData;
OVRPData.Buffer = InData.GetData();
OVRPData.BufferSize = InData.Num();
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().UpdatePassthroughColorLut(
Handle,
OVRPData)))
{
UE_LOG(LogTemp, Error, TEXT("Failed updating passthrough color lut data."));
return;
}
}
void UOculusXRPassthroughColorLut::DestroyLutObject(uint64 Handle) const
{
if (Handle == 0)
{
return;
}
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().DestroyPassthroughColorLut(Handle)))
{
UE_LOG(LogTemp, Error, TEXT("Failed to destroy passthrough color lut."));
}
}
void UOculusXRPassthroughColorLut::BeginDestroy()
{
Super::BeginDestroy();
DestroyLutObject(LutHandle);
}
int UOculusXRPassthroughColorLut::GetMaxResolution()
{
if (MaxResolution > -1)
{
return MaxResolution;
}
ovrpInsightPassthroughCapabilities PassthroughCapabilites;
PassthroughCapabilites.Fields =
static_cast<ovrpInsightPassthroughCapabilityFields>(
ovrpInsightPassthroughCapabilityFields::ovrpInsightPassthroughCapabilityFields_Flags | ovrpInsightPassthroughCapabilityFields::ovrpInsightPassthroughCapabilityFields_MaxColorLutResolution);
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilities(&PassthroughCapabilites)))
{
UE_LOG(LogTemp, Error, TEXT("Failed to fetch passthrough capabilities."));
// Default MAX resoulution is 64.
return 64;
}
MaxResolution = PassthroughCapabilites.MaxColorLutResolution;
return MaxResolution;
}

View File

@@ -0,0 +1,647 @@
// @lint-ignore-every LICENSELINT
// Copyright 1998-2020 Epic Games, Inc. All Rights Reserved.
#include "OculusXRPassthroughLayerComponent.h"
#include "Engine/StaticMesh.h"
#include "Components/StaticMeshComponent.h"
#include "ProceduralMeshComponent.h"
#include "OculusXRHMD.h"
#include "OculusXRPassthroughLayerShapes.h"
#include "Curves/CurveLinearColor.h"
#include "StaticMeshResources.h"
DEFINE_LOG_CATEGORY(LogOculusPassthrough);
void UOculusXRStereoLayerShapeReconstructed::ApplyShape(IStereoLayers::FLayerDesc& LayerDesc)
{
const FEdgeStyleParameters EdgeStyleParameters(
bEnableEdgeColor,
bEnableColorMap,
TextureOpacityFactor,
Brightness,
Contrast,
Posterize,
Saturation,
EdgeColor,
ColorScale,
ColorOffset,
ColorMapType,
GetColorArray(bUseColorMapCurve, ColorMapCurve),
GenerateColorLutDescription(LutWeight, ColorLUTSource, ColorLUTTarget));
LayerDesc.SetShape<FReconstructedLayer>(EdgeStyleParameters, LayerOrder);
}
void UOculusXRStereoLayerShapeUserDefined::ApplyShape(IStereoLayers::FLayerDesc& LayerDesc)
{
//If there is no user geometry, set the layer hidden to avoid unnecessary cost
if (UserGeometryList.IsEmpty())
LayerDesc.Flags |= IStereoLayers::LAYER_FLAG_HIDDEN;
const FEdgeStyleParameters EdgeStyleParameters(
bEnableEdgeColor,
bEnableColorMap,
TextureOpacityFactor,
Brightness,
Contrast,
Posterize,
Saturation,
EdgeColor,
ColorScale,
ColorOffset,
ColorMapType,
GetColorArray(bUseColorMapCurve, ColorMapCurve),
GenerateColorLutDescription(LutWeight, ColorLUTSource, ColorLUTTarget));
LayerDesc.SetShape<FUserDefinedLayer>(UserGeometryList, EdgeStyleParameters, LayerOrder);
}
void UOculusXRStereoLayerShapeUserDefined::AddGeometry(const FString& MeshName, OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh, FTransform Transform, bool bUpdateTransform)
{
FUserDefinedGeometryDesc UserDefinedGeometryDesc(
MeshName,
PassthroughMesh,
Transform,
bUpdateTransform);
UserGeometryList.Add(UserDefinedGeometryDesc);
}
void UOculusXRStereoLayerShapeUserDefined::RemoveGeometry(const FString& MeshName)
{
UserGeometryList.RemoveAll([MeshName](const FUserDefinedGeometryDesc& Desc) {
return Desc.MeshName == MeshName;
});
}
UOculusXRPassthroughLayerComponent::UOculusXRPassthroughLayerComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UOculusXRPassthroughLayerComponent::DestroyComponent(bool bPromoteChildren)
{
Super::DestroyComponent(bPromoteChildren);
#ifdef WITH_OCULUS_BRANCH
IStereoLayers* StereoLayers;
if (LayerId && GEngine->StereoRenderingDevice.IsValid() && (StereoLayers = GEngine->StereoRenderingDevice->GetStereoLayers()) != nullptr)
{
StereoLayers->DestroyLayer(LayerId);
LayerId = 0;
}
#endif
}
void UOculusXRPassthroughLayerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
#ifndef WITH_OCULUS_BRANCH
if (Texture == nullptr && !LayerRequiresTexture())
{
// UStereoLayerComponent hides components without textures
Texture = GEngine->DefaultTexture;
}
#endif
UpdatePassthroughObjects();
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
void UOculusXRPassthroughLayerComponent::UpdatePassthroughObjects()
{
UOculusXRStereoLayerShapeUserDefined* UserShape = Cast<UOculusXRStereoLayerShapeUserDefined>(Shape);
if (UserShape)
{
bool bDirty = false;
for (FUserDefinedGeometryDesc& Entry : UserShape->GetUserGeometryList())
{
if (Entry.bUpdateTransform)
{
const UMeshComponent** MeshComponent = PassthroughComponentMap.Find(Entry.MeshName);
if (MeshComponent)
{
Entry.Transform = (*MeshComponent)->GetComponentTransform();
bDirty = true;
}
}
}
if (bDirty)
{
MarkStereoLayerDirty();
}
}
}
OculusXRHMD::FOculusPassthroughMeshRef UOculusXRPassthroughLayerComponent::CreatePassthroughMesh(UProceduralMeshComponent* ProceduralMeshComponent)
{
if (!ProceduralMeshComponent)
{
UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Procedural Mesh is nullptr"));
return nullptr;
}
TArray<int32> Triangles;
TArray<FVector> Vertices;
int32 NumSections = ProceduralMeshComponent->GetNumSections();
int VertexOffset = 0; //Each section start with vertex IDs of 0, in order to create a single mesh from all sections we need to offset those IDs by the amount of previous vertices
for (int32 s = 0; s < NumSections; ++s)
{
FProcMeshSection* ProcMeshSection = ProceduralMeshComponent->GetProcMeshSection(s);
for (int32 i = 0; i < ProcMeshSection->ProcIndexBuffer.Num(); ++i)
{
Triangles.Add(VertexOffset + ProcMeshSection->ProcIndexBuffer[i]);
}
for (int32 i = 0; i < ProcMeshSection->ProcVertexBuffer.Num(); ++i)
{
Vertices.Add(ProcMeshSection->ProcVertexBuffer[i].Position);
}
VertexOffset += ProcMeshSection->ProcVertexBuffer.Num();
}
OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = new OculusXRHMD::FOculusPassthroughMesh(Vertices, Triangles);
return PassthroughMesh;
}
OculusXRHMD::FOculusPassthroughMeshRef UOculusXRPassthroughLayerComponent::CreatePassthroughMesh(UStaticMeshComponent* StaticMeshComponent)
{
if (!StaticMeshComponent)
{
UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh is nullptr"));
return nullptr;
}
UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh();
if (!Mesh || !Mesh->GetRenderData())
{
UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh has no Renderdata"));
return nullptr;
}
if (Mesh->GetNumLODs() == 0)
{
UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh has no LODs"));
return nullptr;
}
if (!Mesh->bAllowCPUAccess)
{
UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh Requires CPU Access"));
return nullptr;
}
const int32 LODIndex = 0;
FStaticMeshLODResources& LOD = Mesh->GetRenderData()->LODResources[LODIndex];
TArray<int32> Triangles;
const int32 NumIndices = LOD.IndexBuffer.GetNumIndices();
for (int32 i = 0; i < NumIndices; ++i)
{
Triangles.Add(LOD.IndexBuffer.GetIndex(i));
}
TArray<FVector> Vertices;
const int32 NumVertices = LOD.VertexBuffers.PositionVertexBuffer.GetNumVertices();
for (int32 i = 0; i < NumVertices; ++i)
{
Vertices.Add((FVector)LOD.VertexBuffers.PositionVertexBuffer.VertexPosition(i));
}
OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = new OculusXRHMD::FOculusPassthroughMesh(Vertices, Triangles);
return PassthroughMesh;
}
void UOculusXRPassthroughLayerComponent::AddSurfaceGeometry(AStaticMeshActor* StaticMeshActor, bool updateTransform)
{
if (StaticMeshActor)
{
UStaticMeshComponent* StaticMeshComponent = StaticMeshActor->GetStaticMeshComponent();
if (StaticMeshComponent)
AddStaticSurfaceGeometry(StaticMeshComponent, updateTransform);
}
}
void UOculusXRPassthroughLayerComponent::AddStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent, bool updateTransform)
{
if (!StaticMeshComponent)
return;
UOculusXRStereoLayerShapeUserDefined* UserShape = Cast<UOculusXRStereoLayerShapeUserDefined>(Shape);
if (!UserShape)
return;
OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = CreatePassthroughMesh(StaticMeshComponent);
if (!PassthroughMesh)
return;
const FString MeshName = StaticMeshComponent->GetFullName();
const FTransform Transform = StaticMeshComponent->GetComponentTransform();
UserShape->AddGeometry(MeshName, PassthroughMesh, Transform, updateTransform);
PassthroughComponentMap.Add(MeshName, StaticMeshComponent);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerComponent::AddProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent, bool updateTransform)
{
if (!ProceduralMeshComponent)
return;
UOculusXRStereoLayerShapeUserDefined* UserShape = Cast<UOculusXRStereoLayerShapeUserDefined>(Shape);
if (!UserShape)
return;
OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = CreatePassthroughMesh(ProceduralMeshComponent);
if (!PassthroughMesh)
return;
const FString MeshName = ProceduralMeshComponent->GetFullName();
const FTransform Transform = ProceduralMeshComponent->GetComponentTransform();
UserShape->AddGeometry(MeshName, PassthroughMesh, Transform, updateTransform);
PassthroughComponentMap.Add(MeshName, ProceduralMeshComponent);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerComponent::RemoveSurfaceGeometry(AStaticMeshActor* StaticMeshActor)
{
if (StaticMeshActor)
RemoveSurfaceGeometryComponent(StaticMeshActor->GetStaticMeshComponent());
}
void UOculusXRPassthroughLayerComponent::RemoveStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent)
{
RemoveSurfaceGeometryComponent(StaticMeshComponent);
}
void UOculusXRPassthroughLayerComponent::RemoveProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent)
{
RemoveSurfaceGeometryComponent(ProceduralMeshComponent);
}
void UOculusXRPassthroughLayerComponent::RemoveSurfaceGeometryComponent(UMeshComponent* MeshComponent)
{
if (!MeshComponent)
return;
UOculusXRStereoLayerShapeUserDefined* UserShape = Cast<UOculusXRStereoLayerShapeUserDefined>(Shape);
if (!UserShape)
return;
const FString MeshName = MeshComponent->GetFullName();
UserShape->RemoveGeometry(MeshName);
PassthroughComponentMap.Remove(MeshName);
MarkStereoLayerDirty();
}
bool UOculusXRPassthroughLayerComponent::IsSurfaceGeometry(AStaticMeshActor* StaticMeshActor) const
{
return StaticMeshActor ? IsSurfaceGeometryComponent(StaticMeshActor->GetStaticMeshComponent()) : false;
}
bool UOculusXRPassthroughLayerComponent::IsSurfaceGeometryComponent(const UMeshComponent* MeshComponent) const
{
return MeshComponent ? PassthroughComponentMap.Contains(MeshComponent->GetFullName()) : false;
}
void UOculusXRPassthroughLayerComponent::MarkPassthroughStyleForUpdate()
{
bPassthroughStyleNeedsUpdate = true;
}
#if WITH_EDITOR
bool UOculusXRPassthroughLayerComponent::CanEditChange(const FProperty* InProperty) const
{
if (!Super::CanEditChange(InProperty))
return false;
if (!(Shape && Shape.IsA(UOculusXRPassthroughLayerBase::StaticClass())))
{
return true;
}
const FName PropertyName = InProperty->GetFName();
if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, Texture)
|| PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, bQuadPreserveTextureRatio)
|| PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, QuadSize)
|| PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, UVRect)
|| PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, StereoLayerType))
{
return false;
}
return true;
}
#endif // WITH_EDITOR
bool UOculusXRPassthroughLayerComponent::LayerRequiresTexture()
{
const bool bIsPassthroughShape = Shape && (Shape->IsA<UOculusXRStereoLayerShapeReconstructed>() || Shape->IsA<UOculusXRStereoLayerShapeUserDefined>());
return !bIsPassthroughShape;
}
void UOculusXRPassthroughLayerBase::SetTextureOpacity(float InOpacity)
{
if (TextureOpacityFactor == InOpacity)
{
return;
}
TextureOpacityFactor = InOpacity;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::EnableEdgeColor(bool bInEnableEdgeColor)
{
if (bEnableEdgeColor == bInEnableEdgeColor)
{
return;
}
bEnableEdgeColor = bInEnableEdgeColor;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::EnableColorMap(bool bInEnableColorMap)
{
if (bEnableColorMap == bInEnableColorMap)
{
return;
}
bEnableColorMap = bInEnableColorMap;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetEdgeRenderingColor(FLinearColor InEdgeColor)
{
if (EdgeColor == InEdgeColor)
{
return;
}
EdgeColor = InEdgeColor;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::EnableColorMapCurve(bool bInEnableColorMapCurve)
{
if (bUseColorMapCurve == bInEnableColorMapCurve)
{
return;
}
bUseColorMapCurve = bInEnableColorMapCurve;
ColorArray = GenerateColorArray(bUseColorMapCurve, ColorMapCurve);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorMapCurve(UCurveLinearColor* InColorMapCurve)
{
if (ColorMapCurve == InColorMapCurve)
{
return;
}
ColorMapCurve = InColorMapCurve;
ColorArray = GenerateColorArray(bUseColorMapCurve, ColorMapCurve);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorMapType(EOculusXRColorMapType InColorMapType)
{
if (ColorMapType == InColorMapType)
{
return;
}
ColorMapType = InColorMapType;
ColorArray = GenerateColorArray(bUseColorMapCurve, ColorMapCurve);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorArray(const TArray<FLinearColor>& InColorArray)
{
if (InColorArray.Num() == 0)
{
return;
}
if (ColorMapType != ColorMapType_GrayscaleToColor)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorArray is ignored for color map types other than Grayscale to Color."));
return;
}
if (bUseColorMapCurve)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("UseColorMapCurve is enabled on the layer. Automatic disable and use the Array for color lookup"));
}
bUseColorMapCurve = false;
ColorArray = InColorArray;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::ClearColorMap()
{
ColorArray.Empty();
}
void UOculusXRPassthroughLayerBase::SetColorMapControls(float InContrast, float InBrightness, float InPosterize)
{
if (ColorMapType != ColorMapType_Grayscale && ColorMapType != ColorMapType_GrayscaleToColor)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorMapControls is ignored for color map types other than Grayscale and Grayscale to color."));
return;
}
Contrast = FMath::Clamp(InContrast, -1.0f, 1.0f);
Brightness = FMath::Clamp(InBrightness, -1.0f, 1.0f);
Posterize = FMath::Clamp(InPosterize, 0.0f, 1.0f);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetBrightnessContrastSaturation(float InContrast, float InBrightness, float InSaturation)
{
if (ColorMapType != ColorMapType_ColorAdjustment)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("SetBrightnessContrastSaturation is ignored for color map types other than Color Adjustment."));
return;
}
Contrast = FMath::Clamp(InContrast, -1.0f, 1.0f);
Brightness = FMath::Clamp(InBrightness, -1.0f, 1.0f);
Saturation = FMath::Clamp(InSaturation, -1.0f, 1.0f);
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorScaleAndOffset(FLinearColor InColorScale, FLinearColor InColorOffset)
{
if (ColorScale == InColorScale && ColorOffset == InColorOffset)
{
return;
}
ColorScale = InColorScale;
ColorOffset = InColorOffset;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetLayerPlacement(EOculusXRPassthroughLayerOrder InLayerOrder)
{
if (LayerOrder == InLayerOrder)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Same layer order as before, no change needed"));
return;
}
LayerOrder = InLayerOrder;
this->MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorLUTSource(class UOculusXRPassthroughColorLut* InColorLUTSource)
{
if (ColorMapType != ColorMapType_ColorLut && ColorMapType != ColorMapType_ColorLut_Interpolated)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorLUT is ignored for color map types other than Color LUT."));
return;
}
if (InColorLUTSource == ColorLUTSource)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Same color LUT source as before, no change needed"));
return;
}
ColorLUTSource = InColorLUTSource;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorLUTTarget(class UOculusXRPassthroughColorLut* InColorLUTTarget)
{
if (ColorMapType != ColorMapType_ColorLut_Interpolated)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorLUTTarget is ignored for color map types other than Interpolated Color LUT."));
return;
}
if (InColorLUTTarget == ColorLUTTarget)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Same color LUT source as before, no change needed"));
return;
}
ColorLUTTarget = InColorLUTTarget;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::SetColorLUTWeight(float InWeight)
{
if (ColorMapType != ColorMapType_ColorLut && ColorMapType != ColorMapType_ColorLut_Interpolated)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("SetWeight is ignored for color map types other than Color LUT."));
return;
}
if (LutWeight == InWeight)
{
UE_LOG(LogOculusPassthrough, Warning, TEXT("Same lut weight as before, no change needed"));
return;
}
LutWeight = InWeight;
MarkStereoLayerDirty();
}
void UOculusXRPassthroughLayerBase::RemoveColorLut()
{
ColorLUTSource = nullptr;
ColorLUTTarget = nullptr;
MarkStereoLayerDirty();
}
TArray<FLinearColor> UOculusXRPassthroughLayerBase::GenerateColorArrayFromColorCurve(const UCurveLinearColor* InColorMapCurve) const
{
if (InColorMapCurve == nullptr)
{
return TArray<FLinearColor>();
}
TArray<FLinearColor> NewColorArray;
constexpr uint32 TotalEntries = 256;
NewColorArray.Empty();
NewColorArray.SetNum(TotalEntries);
for (int32 Index = 0; Index < TotalEntries; ++Index)
{
const float Alpha = ((float)Index / TotalEntries);
NewColorArray[Index] = InColorMapCurve->GetLinearColorValue(Alpha);
}
return NewColorArray;
}
TArray<FLinearColor> UOculusXRPassthroughLayerBase::GetOrGenerateNeutralColorArray()
{
if (NeutralColorArray.Num() == 0)
{
const uint32 TotalEntries = 256;
NeutralColorArray.SetNum(TotalEntries);
for (int32 Index = 0; Index < TotalEntries; ++Index)
{
NeutralColorArray[Index] = FLinearColor((float)Index / TotalEntries, (float)Index / TotalEntries, (float)Index / TotalEntries);
}
}
return NeutralColorArray;
}
TArray<FLinearColor> UOculusXRPassthroughLayerBase::GenerateColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve)
{
TArray<FLinearColor> NewColorArray;
if (bInUseColorMapCurve)
{
NewColorArray = GenerateColorArrayFromColorCurve(InColorMapCurve);
}
// Check for existing Array, otherwise generate a neutral one
if (NewColorArray.Num() == 0)
{
NewColorArray = GetOrGenerateNeutralColorArray();
}
return NewColorArray;
}
TArray<FLinearColor> UOculusXRPassthroughLayerBase::GetColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve)
{
if (ColorArray.Num() == 0)
{
if (bInUseColorMapCurve)
{
return GenerateColorArray(bInUseColorMapCurve, InColorMapCurve);
}
return GetOrGenerateNeutralColorArray();
}
return ColorArray;
}
FColorLutDesc UOculusXRPassthroughLayerBase::GenerateColorLutDescription(float InLutWeight, UOculusXRPassthroughColorLut* InLutSource, UOculusXRPassthroughColorLut* InLutTarget)
{
TArray<uint64> ColorLuts;
if (InLutSource != nullptr && InLutSource->ColorLutType != EColorLutType::None)
{
uint64 ColorLutHandle = InLutSource->GetHandle();
if (ColorLutHandle != 0)
{
ColorLuts.Add(ColorLutHandle);
}
}
if (ColorMapType == EOculusXRColorMapType::ColorMapType_ColorLut_Interpolated && ColorLuts.Num() > 0 && InLutSource->ColorLutType != EColorLutType::None)
{
uint64 ColorLutHandle = InLutTarget->GetHandle();
if (ColorLutHandle != 0)
{
ColorLuts.Add(ColorLutHandle);
}
}
return FColorLutDesc(ColorLuts, InLutWeight);
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRPassthroughModule.h"
#define LOCTEXT_NAMESPACE "OculusXRPassthrough"
//-------------------------------------------------------------------------------------------------
// FOculusXRPassthroughModule
//-------------------------------------------------------------------------------------------------
FOculusXRPassthroughModule::FOculusXRPassthroughModule()
{
}
void FOculusXRPassthroughModule::StartupModule()
{
}
void FOculusXRPassthroughModule::ShutdownModule()
{
}
IMPLEMENT_MODULE(FOculusXRPassthroughModule, OculusXRPassthrough)
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,26 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "IOculusXRPassthroughModule.h"
#define LOCTEXT_NAMESPACE "OculusXRPassthrough"
//-------------------------------------------------------------------------------------------------
// FOculusXRPassthroughModule
//-------------------------------------------------------------------------------------------------
class FOculusXRPassthroughModule : public IOculusXRPassthroughModule
{
public:
FOculusXRPassthroughModule();
static inline FOculusXRPassthroughModule& Get()
{
return FModuleManager::LoadModuleChecked<FOculusXRPassthroughModule>("OculusXRPassthrough");
}
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,35 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
/**
* The public interface to this module. In most cases, this interface is only public to sibling modules
* within this plugin.
*/
class IOculusXRPassthroughModule : public IModuleInterface
{
public:
/**
* Singleton-like access to this module's interface. This is just for convenience!
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
*
* @return Returns singleton instance, loading the module on demand if needed
*/
static inline IOculusXRPassthroughModule& Get()
{
return FModuleManager::GetModuleChecked<IOculusXRPassthroughModule>("OculusXRPassthrough");
}
/**
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
*
* @return True if the module is loaded and ready to use
*/
static inline bool IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("OculusXRPassthrough");
}
};

View File

@@ -0,0 +1,80 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Engine/Texture2D.h"
#include "OculusXRPassthroughColorLut.generated.h"
enum EColorLutChannels
{
ColorLutChannels_RGB,
ColorLutChannels_RGBA
};
USTRUCT()
struct FLutTextureData
{
GENERATED_BODY()
public:
UPROPERTY()
TArray<uint8> Data;
UPROPERTY()
uint32 Resolution;
FLutTextureData()
: Data{}, Resolution(0) {}
FLutTextureData(const TArray<uint8>& InData, uint32 InResolution)
: Data(InData), Resolution(InResolution) {}
};
UENUM(BlueprintType)
enum class EColorLutType : uint8
{
None = 0 UMETA(DisplayName = "None"),
TextureLUT = 1 UMETA(DisplayName = "Texture"),
Array = 2 UMETA(Hidden)
};
UCLASS(BlueprintType, CollapseCategories, meta = (DisplayName = "Passthrough Color LUT"))
class OCULUSXRPASSTHROUGH_API UOculusXRPassthroughColorLut : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Color LUT")
EColorLutType ColorLutType = EColorLutType::None;
#if WITH_EDITORONLY_DATA
/** Color LUT texture.*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Color LUT", meta = (EditCondition = "ColorLutType == EColorLutType::TextureLUT", EditConditionHides))
UTexture2D* LutTexture;
#endif
/** If alpha channel should be ignored.*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Color LUT", meta = (EditCondition = "ColorLutType == EColorLutType::TextureLUT", EditConditionHides))
bool IgnoreAlphaChannel = false;
/** Generate color LUT from array. Array should have format of exploded cube. Its size should be power of 2. */
UFUNCTION(BlueprintCallable, Category = "Passthrough Color LUT")
void SetLutFromArray(const TArray<FColor>& InColorArray, bool InIgnoreAlphaChannel);
uint64 GetHandle();
virtual void PreSave(FObjectPreSaveContext ObjectSaveContext) override;
void BeginDestroy() override;
private:
UPROPERTY()
FLutTextureData StoredTextureData;
uint64 LutHandle = 0;
int32 ColorArrayResolution = 0;
int MaxResolution = -1;
FLutTextureData TextureToColorData(class UTexture2D* InLutTexture) const;
uint64 CreateLutObject(const TArray<uint8>& InData, uint32 Resolution) const;
void UpdateLutObject(uint64 Handle, const TArray<uint8>& InData) const;
void DestroyLutObject(uint64 Handle) const;
int GetMaxResolution();
};

View File

@@ -0,0 +1,259 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
// OculusEventComponent.h: Component to handle receiving events from Oculus HMDs
#pragma once
#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "UObject/ObjectMacros.h"
#include "Components/StereoLayerComponent.h"
#include "OculusXRPassthroughLayerShapes.h"
#include "OculusXRPassthroughColorLut.h"
#include "OculusXRHMDRuntimeSettings.h"
#include "OculusXRPassthroughLayerComponent.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogOculusPassthrough, Log, All);
UCLASS(Abstract, meta = (DisplayName = "Passthrough Layer Base"))
class OCULUSXRPASSTHROUGH_API UOculusXRPassthroughLayerBase : public UStereoLayerShape
{
GENERATED_BODY()
public:
/** Ordering of passthrough layer in relation to scene rendering */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", DisplayName = "Layer Placement")
TEnumAsByte<enum EOculusXRPassthroughLayerOrder> LayerOrder;
/** Opacity of the (main) passthrough texture. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (UIMin = 0.0, UIMax = 1.0, ClampMin = 0.0, ClampMax = 1.0))
float TextureOpacityFactor = 1.0f;
/** Enable edge color */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (DisplayName = "Enable Edge Rendering"))
bool bEnableEdgeColor = false;
/** Color of the passthrough edge rendering effect. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties")
FLinearColor EdgeColor;
/** Enable color mapping */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties")
bool bEnableColorMap = false;
/** Type of colormapping to perform */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap", EditConditionHides))
TEnumAsByte<enum EOculusXRColorMapType> ColorMapType;
/** Whether to use color map curve or gradient*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && ColorMapType == 1", EditConditionHides))
bool bUseColorMapCurve = false;
/** Passthrough color mapping gradient converts grayscale to color*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && bUseColorMapCurve && ColorMapType == 1", EditConditionHides))
UCurveLinearColor* ColorMapCurve;
/** Contrast setting for color mapping*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "-1", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 0 && ColorMapType < 4", EditConditionHides))
float Contrast = 0.0f;
/** Brightness setting for color mapping*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "-1", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 0 && ColorMapType < 4", EditConditionHides))
float Brightness = 0.0f;
/** Posterize setting for grayscale and grayscale to color mapping*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "0", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 0 && ColorMapType < 3", EditConditionHides))
float Posterize = 0.0f;
/** Saturation setting for color adjustment mapping*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "-1", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType == 3", EditConditionHides))
float Saturation = 0.0f;
/** Color LUT Weight. It is used to combine LUT with Passthrough if one LUT is provided. If two LUTs are provided LutWeight will be used to blend them. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "0", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 3", EditConditionHides))
float LutWeight = 1.0f;
/**
* Color LUT properties. If only ColorLUTSource is provided it will be blended with passthrough layer using following formula:
* Result = ColorLUTSource * LutWeight + Passthrough * (1 - LutWeight )
*/
UPROPERTY(EditAnywhere, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && ColorMapType > 3", EditConditionHides))
UOculusXRPassthroughColorLut* ColorLUTSource;
/**
* Color LUT properties. If two LUTs are provided they will be blended using following formula:
* Result = ColorLUTsSource * ( 1 - LutWeight ) + ColorLUTsTarget * LutWeight
*/
UPROPERTY(EditAnywhere, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && ColorMapType > 4", EditConditionHides))
UOculusXRPassthroughColorLut* ColorLUTTarget;
/** Color value that will be multiplied to the current color map*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap", EditConditionHides))
FLinearColor ColorScale = FLinearColor::White;
/** Color value that will be added to the current color map*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap", EditConditionHides))
FLinearColor ColorOffset = FLinearColor::Black;
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetTextureOpacity(float InOpacity);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void EnableEdgeColor(bool bInEnableEdgeColor);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void EnableColorMap(bool bInEnableColorMap);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void EnableColorMapCurve(bool bInEnableColorMapCurve);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetEdgeRenderingColor(FLinearColor InEdgeColor);
/** Set color map controls for grayscale and grayscale to rgb color mapping*/
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorMapControls(float InContrast = 0, float InBrightness = 0, float InPosterize = 0);
/** Set color map controls for color adjustment color mapping */
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetBrightnessContrastSaturation(float InContrast = 0, float InBrightness = 0, float InSaturation = 0);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorScaleAndOffset(FLinearColor InColorScale = FLinearColor::White, FLinearColor InColorOffset = FLinearColor::Black);
/** Set color curve that will be added to the color map in grayscale modes --> will be converted into a gradient*/
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorMapCurve(UCurveLinearColor* InColorMapCurve);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorMapType(EOculusXRColorMapType InColorMapType);
/** Set color map array directly instead through a color curve*/
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorArray(const TArray<FLinearColor>& InColorArray);
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void ClearColorMap();
UFUNCTION(BlueprintCallable, Category = "Passthrough Properties")
void SetLayerPlacement(EOculusXRPassthroughLayerOrder InLayerOrder);
/**
* Sets Color LUT source.
* If ColorMapType is "Color LUT", then source will be blended with passthrough
* using folowing formula:
* Result = ColorLUTSource * LutWeight + Passthrough * (1 - LutWeight )
* If ColorMapType is "Interpolated Color LUT", then source will be blended with color LUT target
* using folowing formula:
* Result = ColorLUTSource * ( 1 - LutWeight ) + ColorLUTTarget * LutWeight
*/
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorLUTSource(class UOculusXRPassthroughColorLut* InColorLUTSource);
/**
* Sets Color LUT target.
* If ColorMapType is "Interpolated Color LUT", then target will be blended with passthrough
* using folowing formula:
* Result = ColorLUTSource * ( 1 - LutWeight ) + ColorLUTTarget * LutWeight
* Note: If ColorLUTSource is not specified, Color LUT will be not be applied to the Passthrough layer.
*/
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorLUTTarget(class UOculusXRPassthroughColorLut* InColorLUTTarget);
/** Sets LUT weight. */
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void SetColorLUTWeight(float InWeight = 1.0f);
/** Removes color grading if any is active. */
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void RemoveColorLut();
protected:
TArray<FLinearColor> ColorArray;
TArray<FLinearColor> NeutralColorArray;
TArray<FLinearColor> GenerateColorArrayFromColorCurve(const UCurveLinearColor* InColorMapCurve) const;
TArray<FLinearColor> GetOrGenerateNeutralColorArray();
TArray<FLinearColor> GenerateColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve);
TArray<FLinearColor> GetColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve);
FColorLutDesc GenerateColorLutDescription(float InLutWeight, UOculusXRPassthroughColorLut* InLutSource, UOculusXRPassthroughColorLut* InLutTarget);
};
/* Reconstructed Passthrough Layer*/
UCLASS(meta = (DisplayName = "Reconstructed Passthrough Layer"))
class OCULUSXRPASSTHROUGH_API UOculusXRStereoLayerShapeReconstructed : public UOculusXRPassthroughLayerBase
{
GENERATED_BODY()
public:
virtual void ApplyShape(IStereoLayers::FLayerDesc& LayerDesc) override;
};
/* User Defined Passthrough Layer*/
UCLASS(meta = (DisplayName = "User Defined Passthrough Layer"))
class OCULUSXRPASSTHROUGH_API UOculusXRStereoLayerShapeUserDefined : public UOculusXRPassthroughLayerBase
{
GENERATED_BODY()
public:
void AddGeometry(const FString& MeshName, OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh, FTransform Transform, bool bUpdateTransform);
void RemoveGeometry(const FString& MeshName);
virtual void ApplyShape(IStereoLayers::FLayerDesc& LayerDesc) override;
TArray<FUserDefinedGeometryDesc>& GetUserGeometryList() { return UserGeometryList; };
private:
TArray<FUserDefinedGeometryDesc> UserGeometryList;
};
class UProceduralMeshComponent;
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = OculusXRHMD)
class OCULUSXRPASSTHROUGH_API UOculusXRPassthroughLayerComponent : public UStereoLayerComponent
{
GENERATED_UCLASS_BODY()
public:
void DestroyComponent(bool bPromoteChildren) override;
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
void UpdatePassthroughObjects();
UFUNCTION(BlueprintCallable, Category = "Passthrough", meta = (DeprecatedFunction, DeprecationMessage = "Please use AddStaticSurfaceGeometry instead"))
void AddSurfaceGeometry(AStaticMeshActor* StaticMeshActor, bool updateTransform);
UFUNCTION(BlueprintCallable, Category = "Passthrough")
void AddStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent, bool updateTransform);
UFUNCTION(BlueprintCallable, Category = "Passthrough")
void AddProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent, bool updateTransform);
UFUNCTION(BlueprintCallable, Category = "Passthrough", meta = (DeprecatedFunction, DeprecationMessage = "Please use RemoveStaticSurfaceGeometry instead"))
void RemoveSurfaceGeometry(AStaticMeshActor* StaticMeshActor);
UFUNCTION(BlueprintCallable, Category = "Passthrough")
void RemoveStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent);
UFUNCTION(BlueprintCallable, Category = "Passthrough")
void RemoveProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent);
UFUNCTION(BlueprintCallable, Category = "Passthrough", meta = (DeprecatedFunction, DeprecationMessage = "Please use IsSurfaceGeometryComponent instead"))
bool IsSurfaceGeometry(AStaticMeshActor* StaticMeshActor) const;
UFUNCTION(BlueprintPure, Category = "Passthrough")
bool IsSurfaceGeometryComponent(const UMeshComponent* MeshComponent) const;
// Manually mark the stereo layer passthrough effect for updating
UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer")
void MarkPassthroughStyleForUpdate();
#if WITH_EDITOR
virtual bool CanEditChange(const FProperty* InProperty) const override;
#endif // WITH_EDITOR
protected:
virtual bool LayerRequiresTexture();
virtual void RemoveSurfaceGeometryComponent(UMeshComponent* MeshComponent);
UPROPERTY(Transient)
TMap<FString, const UMeshComponent*> PassthroughComponentMap;
private:
OculusXRHMD::FOculusPassthroughMeshRef CreatePassthroughMesh(UProceduralMeshComponent* ProceduralMeshComponent);
OculusXRHMD::FOculusPassthroughMeshRef CreatePassthroughMesh(UStaticMeshComponent* StaticMeshComponent);
/** Passthrough style needs to be marked for update **/
bool bPassthroughStyleNeedsUpdate;
};