271 lines
8.7 KiB
C++
271 lines
8.7 KiB
C++
|
// @lint-ignore-every LICENSELINT
|
||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
||
|
#include "OculusXRMR_PlaneMeshComponent.h"
|
||
|
#include "RenderingThread.h"
|
||
|
#include "RenderResource.h"
|
||
|
#include "PrimitiveViewRelevance.h"
|
||
|
#include "PrimitiveSceneProxy.h"
|
||
|
#include "VertexFactory.h"
|
||
|
#include "Engine/CollisionProfile.h"
|
||
|
#include "Engine/TextureRenderTarget2D.h"
|
||
|
#include "Materials/Material.h"
|
||
|
#include "LocalVertexFactory.h"
|
||
|
#include "SceneManagement.h"
|
||
|
#include "DynamicMeshBuilder.h"
|
||
|
#include "EngineGlobals.h"
|
||
|
#include "Engine/Engine.h"
|
||
|
#include "MaterialShared.h"
|
||
|
#include "SceneInterface.h"
|
||
|
#include "TextureResource.h"
|
||
|
#include "MaterialDomain.h"
|
||
|
#include "Materials/MaterialRenderProxy.h"
|
||
|
|
||
|
/** Scene proxy */
|
||
|
class FOculusXRMR_PlaneMeshSceneProxy : public FPrimitiveSceneProxy
|
||
|
{
|
||
|
public:
|
||
|
FOculusXRMR_PlaneMeshSceneProxy(UOculusXRMR_PlaneMeshComponent* Component, UTextureRenderTarget2D* RenderTarget)
|
||
|
: FPrimitiveSceneProxy(Component)
|
||
|
, MaterialRelevance(Component->GetMaterialRelevance(GetScene().GetFeatureLevel()))
|
||
|
, PlaneRenderTarget(RenderTarget)
|
||
|
{
|
||
|
const FColor VertexColor(255, 255, 255);
|
||
|
|
||
|
const int32 NumTris = Component->CustomMeshTris.Num();
|
||
|
Vertices.AddUninitialized(NumTris * 3);
|
||
|
Indices.AddUninitialized(NumTris * 3);
|
||
|
// Add each triangle to the vertex/index buffer
|
||
|
for (int32 TriIdx = 0; TriIdx < NumTris; TriIdx++)
|
||
|
{
|
||
|
FOculusXRMR_PlaneMeshTriangle& Tri = Component->CustomMeshTris[TriIdx];
|
||
|
|
||
|
const FVector Edge01 = (Tri.Vertex1 - Tri.Vertex0);
|
||
|
const FVector Edge02 = (Tri.Vertex2 - Tri.Vertex0);
|
||
|
|
||
|
const FVector TangentX = Edge01.GetSafeNormal();
|
||
|
const FVector TangentZ = (Edge02 ^ Edge01).GetSafeNormal();
|
||
|
const FVector TangentY = (TangentX ^ TangentZ).GetSafeNormal();
|
||
|
|
||
|
FDynamicMeshVertex Vert;
|
||
|
|
||
|
Vert.Color = VertexColor;
|
||
|
Vert.SetTangents((FVector3f)TangentX, (FVector3f)TangentY, (FVector3f)TangentZ);
|
||
|
|
||
|
Vert.Position = (FVector3f)Tri.Vertex0;
|
||
|
Vert.TextureCoordinate[0] = FVector2f(Tri.UV0); // LWC_TODO: Precision loss
|
||
|
Vertices[TriIdx * 3 + 0] = Vert;
|
||
|
Indices[TriIdx * 3 + 0] = TriIdx * 3 + 0;
|
||
|
|
||
|
Vert.Position = (FVector3f)Tri.Vertex1;
|
||
|
Vert.TextureCoordinate[0] = FVector2f(Tri.UV1); // LWC_TODO: Precision loss
|
||
|
Vertices[TriIdx * 3 + 1] = Vert;
|
||
|
Indices[TriIdx * 3 + 1] = TriIdx * 3 + 1;
|
||
|
|
||
|
Vert.Position = (FVector3f)Tri.Vertex2;
|
||
|
Vert.TextureCoordinate[0] = FVector2f(Tri.UV2); // LWC_TODO: Precision loss
|
||
|
Vertices[TriIdx * 3 + 2] = Vert;
|
||
|
Indices[TriIdx * 3 + 2] = TriIdx * 3 + 2;
|
||
|
}
|
||
|
|
||
|
// Grab material
|
||
|
Material = Component->GetMaterial(0);
|
||
|
if (Material == nullptr)
|
||
|
{
|
||
|
Material = UMaterial::GetDefaultMaterial(MD_Surface);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual ~FOculusXRMR_PlaneMeshSceneProxy()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
SIZE_T GetTypeHash() const override
|
||
|
{
|
||
|
static size_t UniquePointer;
|
||
|
return reinterpret_cast<size_t>(&UniquePointer);
|
||
|
}
|
||
|
|
||
|
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
|
||
|
{
|
||
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_OculusXRMR_PlaneMeshSceneProxy_GetDynamicMeshElements);
|
||
|
|
||
|
// the mesh is only visible inside the CastingViewport, and the Full CastingLayer (the Composition mode)
|
||
|
if (PlaneRenderTarget && ViewFamily.RenderTarget == PlaneRenderTarget->GetRenderTargetResource())
|
||
|
{
|
||
|
const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe;
|
||
|
|
||
|
FMaterialRenderProxy* MaterialProxy = nullptr;
|
||
|
if (bWireframe)
|
||
|
{
|
||
|
auto WireframeMaterialInstance = new FColoredMaterialRenderProxy(
|
||
|
GEngine->WireframeMaterial->GetRenderProxy(),
|
||
|
FLinearColor(0, 0.5f, 1.f));
|
||
|
|
||
|
Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance);
|
||
|
MaterialProxy = WireframeMaterialInstance;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MaterialProxy = Material->GetRenderProxy();
|
||
|
}
|
||
|
|
||
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
||
|
{
|
||
|
if (VisibilityMap & (1 << ViewIndex))
|
||
|
{
|
||
|
const FSceneView* View = Views[ViewIndex];
|
||
|
|
||
|
FDynamicMeshBuilder DynamicMeshBuilder(View->GetFeatureLevel());
|
||
|
DynamicMeshBuilder.AddVertices(Vertices);
|
||
|
DynamicMeshBuilder.AddTriangles(Indices);
|
||
|
|
||
|
DynamicMeshBuilder.GetMesh(GetLocalToWorld(), MaterialProxy, SDPG_World, true, false, ViewIndex, Collector);
|
||
|
|
||
|
// -- Original draw code for reference --
|
||
|
//FMeshBatch& Mesh = Collector.AllocateMesh();
|
||
|
//FMeshBatchElement& BatchElement = Mesh.Elements[0];
|
||
|
//BatchElement.IndexBuffer = &IndexBuffer;
|
||
|
//Mesh.bWireframe = bWireframe;
|
||
|
//Mesh.VertexFactory = &VertexFactory;
|
||
|
//Mesh.MaterialRenderProxy = MaterialProxy;
|
||
|
//BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, DrawsVelocity());
|
||
|
//BatchElement.FirstIndex = 0;
|
||
|
//BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;
|
||
|
//BatchElement.MinVertexIndex = 0;
|
||
|
//BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1;
|
||
|
//Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
|
||
|
//Mesh.Type = PT_TriangleList;
|
||
|
//Mesh.DepthPriorityGroup = SDPG_World;
|
||
|
//Mesh.bCanApplyViewModeOverrides = false;
|
||
|
//Collector.AddMesh(ViewIndex, Mesh);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
|
||
|
{
|
||
|
FPrimitiveViewRelevance Result;
|
||
|
Result.bDrawRelevance = IsShown(View);
|
||
|
Result.bShadowRelevance = IsShadowCast(View);
|
||
|
Result.bDynamicRelevance = true;
|
||
|
Result.bRenderInMainPass = ShouldRenderInMainPass();
|
||
|
Result.bUsesLightingChannels = GetLightingChannelMask() != GetDefaultLightingChannelMask();
|
||
|
Result.bRenderCustomDepth = ShouldRenderCustomDepth();
|
||
|
MaterialRelevance.SetPrimitiveViewRelevance(Result);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
virtual bool CanBeOccluded() const override
|
||
|
{
|
||
|
return !MaterialRelevance.bDisableDepthTest;
|
||
|
}
|
||
|
|
||
|
virtual uint32 GetMemoryFootprint(void) const override { return (sizeof(*this) + GetAllocatedSize()); }
|
||
|
|
||
|
uint32 GetAllocatedSize(void) const { return (FPrimitiveSceneProxy::GetAllocatedSize()); }
|
||
|
|
||
|
private:
|
||
|
UMaterialInterface* Material;
|
||
|
TArray<FDynamicMeshVertex> Vertices;
|
||
|
TArray<uint32> Indices;
|
||
|
FMaterialRelevance MaterialRelevance;
|
||
|
UTextureRenderTarget2D* PlaneRenderTarget;
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
UOculusXRMR_PlaneMeshComponent::UOculusXRMR_PlaneMeshComponent(const FObjectInitializer& ObjectInitializer)
|
||
|
: Super(ObjectInitializer)
|
||
|
{
|
||
|
PrimaryComponentTick.bCanEverTick = false;
|
||
|
|
||
|
SetCollisionProfileName(UCollisionProfile::BlockAllDynamic_ProfileName);
|
||
|
|
||
|
bRenderCustomDepth = true;
|
||
|
}
|
||
|
|
||
|
bool UOculusXRMR_PlaneMeshComponent::SetCustomMeshTriangles(const TArray<FOculusXRMR_PlaneMeshTriangle>& Triangles)
|
||
|
{
|
||
|
CustomMeshTris = Triangles;
|
||
|
|
||
|
// Need to recreate scene proxy to send it over
|
||
|
MarkRenderStateDirty();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void UOculusXRMR_PlaneMeshComponent::AddCustomMeshTriangles(const TArray<FOculusXRMR_PlaneMeshTriangle>& Triangles)
|
||
|
{
|
||
|
CustomMeshTris.Append(Triangles);
|
||
|
|
||
|
// Need to recreate scene proxy to send it over
|
||
|
MarkRenderStateDirty();
|
||
|
}
|
||
|
|
||
|
void UOculusXRMR_PlaneMeshComponent::ClearCustomMeshTriangles()
|
||
|
{
|
||
|
CustomMeshTris.Reset();
|
||
|
|
||
|
// Need to recreate scene proxy to send it over
|
||
|
MarkRenderStateDirty();
|
||
|
}
|
||
|
|
||
|
void UOculusXRMR_PlaneMeshComponent::Place(const FVector& Center, const FVector& Up, const FVector& Normal, const FVector2D& Size)
|
||
|
{
|
||
|
FVector Right = FVector::CrossProduct(Up, Normal);
|
||
|
|
||
|
FVector Up_N = Up.GetUnsafeNormal();
|
||
|
FVector Right_N = Right.GetUnsafeNormal();
|
||
|
|
||
|
FVector V0 = Center - Right_N * Size.X * 0.5f - Up_N * Size.Y * 0.5f;
|
||
|
FVector2D UV0(1, 1);
|
||
|
FVector V1 = Center + Right_N * Size.X * 0.5f - Up_N * Size.Y * 0.5f;
|
||
|
FVector2D UV1(0, 1);
|
||
|
FVector V2 = Center - Right_N * Size.X * 0.5f + Up_N * Size.Y * 0.5f;
|
||
|
FVector2D UV2(1, 0);
|
||
|
FVector V3 = Center + Right_N * Size.X * 0.5f + Up_N * Size.Y * 0.5f;
|
||
|
FVector2D UV3(0, 0);
|
||
|
|
||
|
FOculusXRMR_PlaneMeshTriangle Tri0, Tri1;
|
||
|
Tri0.Vertex0 = V1;
|
||
|
Tri0.UV0 = UV1;
|
||
|
Tri0.Vertex1 = V0;
|
||
|
Tri0.UV1 = UV0;
|
||
|
Tri0.Vertex2 = V2;
|
||
|
Tri0.UV2 = UV2;
|
||
|
Tri1.Vertex0 = V1;
|
||
|
Tri1.UV0 = UV1;
|
||
|
Tri1.Vertex1 = V2;
|
||
|
Tri1.UV1 = UV2;
|
||
|
Tri1.Vertex2 = V3;
|
||
|
Tri1.UV2 = UV3;
|
||
|
|
||
|
SetCustomMeshTriangles({ Tri0, Tri1 });
|
||
|
}
|
||
|
|
||
|
FPrimitiveSceneProxy* UOculusXRMR_PlaneMeshComponent::CreateSceneProxy()
|
||
|
{
|
||
|
FPrimitiveSceneProxy* Proxy = nullptr;
|
||
|
if (CustomMeshTris.Num() > 0)
|
||
|
{
|
||
|
Proxy = new FOculusXRMR_PlaneMeshSceneProxy(this, PlaneRenderTarget);
|
||
|
}
|
||
|
return Proxy;
|
||
|
}
|
||
|
|
||
|
int32 UOculusXRMR_PlaneMeshComponent::GetNumMaterials() const
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
FBoxSphereBounds UOculusXRMR_PlaneMeshComponent::CalcBounds(const FTransform& LocalToWorld) const
|
||
|
{
|
||
|
FBoxSphereBounds NewBounds;
|
||
|
NewBounds.Origin = FVector::ZeroVector;
|
||
|
NewBounds.BoxExtent = FVector(HALF_WORLD_MAX, HALF_WORLD_MAX, HALF_WORLD_MAX);
|
||
|
NewBounds.SphereRadius = FMath::Sqrt(3.0f * FMath::Square(HALF_WORLD_MAX));
|
||
|
return NewBounds;
|
||
|
}
|