2015-06-18 06:59:14 -04:00
|
|
|
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "GeometryCacheModulePrivatePCH.h"
|
|
|
|
|
#include "GeometryCacheSceneProxy.h"
|
2015-06-18 18:46:15 -04:00
|
|
|
#include "GeometryCacheComponent.h"
|
|
|
|
|
#include "GeometryCacheMeshData.h"
|
2015-06-18 06:59:14 -04:00
|
|
|
|
|
|
|
|
FGeometryCacheSceneProxy::FGeometryCacheSceneProxy(UGeometryCacheComponent* Component) : FPrimitiveSceneProxy(Component)
|
|
|
|
|
, MaterialRelevance(Component->GetMaterialRelevance(GetScene().GetFeatureLevel()))
|
|
|
|
|
{
|
|
|
|
|
// Copy each section
|
|
|
|
|
const int32 NumSections = Component->TrackSections.Num();
|
|
|
|
|
Sections.AddZeroed(NumSections);
|
|
|
|
|
for (int SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
|
|
|
|
|
{
|
|
|
|
|
FTrackRenderData& SrcSection = Component->TrackSections[SectionIdx];
|
|
|
|
|
|
|
|
|
|
if (SrcSection.IndexBuffer.Num() > 0)
|
|
|
|
|
{
|
|
|
|
|
FGeomCacheTrackProxy* NewSection = new FGeomCacheTrackProxy();
|
|
|
|
|
|
|
|
|
|
NewSection->WorldMatrix = SrcSection.WorldMatrix;
|
|
|
|
|
FGeometryCacheMeshData* MeshData = NewSection->MeshData = SrcSection.MeshData;
|
|
|
|
|
|
|
|
|
|
// Copy data from vertex buffer
|
|
|
|
|
const int32 NumVerts = MeshData->Vertices.Num();
|
|
|
|
|
|
|
|
|
|
// Allocate verts
|
|
|
|
|
NewSection->VertexBuffer.Vertices.Empty(NumVerts);
|
|
|
|
|
// Copy verts
|
|
|
|
|
NewSection->VertexBuffer.Vertices.Append(MeshData->Vertices);
|
|
|
|
|
|
|
|
|
|
// Copy index buffer
|
|
|
|
|
NewSection->IndexBuffer.Indices = SrcSection.IndexBuffer;
|
|
|
|
|
|
|
|
|
|
// Init vertex factory
|
|
|
|
|
NewSection->VertexFactory.Init(&NewSection->VertexBuffer);
|
|
|
|
|
|
|
|
|
|
// Enqueue initialization of render resource
|
|
|
|
|
BeginInitResource(&NewSection->VertexBuffer);
|
|
|
|
|
BeginInitResource(&NewSection->IndexBuffer);
|
|
|
|
|
BeginInitResource(&NewSection->VertexFactory);
|
|
|
|
|
|
|
|
|
|
// Grab materials
|
|
|
|
|
for (FGeometryCacheMeshBatchInfo& BatchInfo : MeshData->BatchesInfo)
|
|
|
|
|
{
|
|
|
|
|
UMaterialInterface* Material = Component->GetMaterial(BatchInfo.MaterialIndex);
|
|
|
|
|
if (Material == NULL)
|
|
|
|
|
{
|
|
|
|
|
Material = UMaterial::GetDefaultMaterial(MD_Surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NewSection->Materials.Push(Material);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save ref to new section
|
|
|
|
|
Sections[SectionIdx] = NewSection;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGeometryCacheSceneProxy::~FGeometryCacheSceneProxy()
|
|
|
|
|
{
|
|
|
|
|
for (FGeomCacheTrackProxy* Section : Sections)
|
|
|
|
|
{
|
|
|
|
|
if (Section != nullptr)
|
|
|
|
|
{
|
|
|
|
|
Section->VertexBuffer.ReleaseResource();
|
|
|
|
|
Section->IndexBuffer.ReleaseResource();
|
|
|
|
|
Section->VertexFactory.ReleaseResource();
|
|
|
|
|
delete Section;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Sections.Empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeometryCacheSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
|
|
|
|
|
{
|
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_GeometryCacheSceneProxy_GetMeshElements);
|
|
|
|
|
|
|
|
|
|
// Set up wireframe material (if needed)
|
|
|
|
|
const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe;
|
|
|
|
|
|
|
|
|
|
FColoredMaterialRenderProxy* WireframeMaterialInstance = NULL;
|
|
|
|
|
if (bWireframe)
|
|
|
|
|
{
|
|
|
|
|
WireframeMaterialInstance = new FColoredMaterialRenderProxy(
|
|
|
|
|
GEngine->WireframeMaterial ? GEngine->WireframeMaterial->GetRenderProxy(IsSelected()) : NULL,
|
|
|
|
|
FLinearColor(0, 0.5f, 1.f)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iterate over sections
|
|
|
|
|
for (const FGeomCacheTrackProxy* TrackProxy : Sections )
|
|
|
|
|
{
|
|
|
|
|
// QQQ
|
|
|
|
|
if (TrackProxy != nullptr)
|
|
|
|
|
{
|
|
|
|
|
INC_DWORD_STAT_BY(STAT_GeometryCacheSceneProxy_MeshBatchCount, TrackProxy->MeshData->BatchesInfo.Num());
|
|
|
|
|
|
|
|
|
|
int32 BatchIndex = 0;
|
|
|
|
|
for (FGeometryCacheMeshBatchInfo& BatchInfo : TrackProxy->MeshData->BatchesInfo)
|
|
|
|
|
{
|
|
|
|
|
FMaterialRenderProxy* MaterialProxy = bWireframe ? WireframeMaterialInstance : TrackProxy->Materials[BatchIndex]->GetRenderProxy(IsSelected());
|
|
|
|
|
|
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
|
|
|
{
|
|
|
|
|
if (VisibilityMap & (1 << ViewIndex))
|
|
|
|
|
{
|
|
|
|
|
const FSceneView* View = Views[ViewIndex];
|
|
|
|
|
// Draw the mesh.
|
|
|
|
|
FMeshBatch& Mesh = Collector.AllocateMesh();
|
|
|
|
|
FMeshBatchElement& BatchElement = Mesh.Elements[0];
|
|
|
|
|
BatchElement.IndexBuffer = &TrackProxy->IndexBuffer;
|
|
|
|
|
Mesh.bWireframe = bWireframe;
|
|
|
|
|
Mesh.VertexFactory = &TrackProxy->VertexFactory;
|
|
|
|
|
Mesh.MaterialRenderProxy = MaterialProxy;
|
|
|
|
|
BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(TrackProxy->WorldMatrix * GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, UseEditorDepthTest());
|
|
|
|
|
BatchElement.FirstIndex = BatchInfo.StartIndex;
|
|
|
|
|
BatchElement.NumPrimitives = BatchInfo.NumTriangles;
|
|
|
|
|
BatchElement.MinVertexIndex = 0;
|
|
|
|
|
BatchElement.MaxVertexIndex = TrackProxy->VertexBuffer.Vertices.Num() - 1;
|
|
|
|
|
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
|
|
|
|
|
Mesh.Type = PT_TriangleList;
|
|
|
|
|
Mesh.DepthPriorityGroup = SDPG_World;
|
|
|
|
|
Mesh.bCanApplyViewModeOverrides = false;
|
|
|
|
|
Collector.AddMesh(ViewIndex, Mesh);
|
|
|
|
|
|
|
|
|
|
INC_DWORD_STAT_BY(STAT_GeometryCacheSceneProxy_TriangleCount, BatchElement.NumPrimitives);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++BatchIndex;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw bounds
|
|
|
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
|
|
|
{
|
|
|
|
|
if (VisibilityMap & (1 << ViewIndex))
|
|
|
|
|
{
|
|
|
|
|
// Render bounds
|
|
|
|
|
RenderBounds(Collector.GetPDI(ViewIndex), ViewFamily.EngineShowFlags, GetBounds(), IsSelected());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FPrimitiveViewRelevance FGeometryCacheSceneProxy::GetViewRelevance(const FSceneView* View)
|
|
|
|
|
{
|
|
|
|
|
FPrimitiveViewRelevance Result;
|
|
|
|
|
Result.bDrawRelevance = IsShown(View);
|
|
|
|
|
Result.bShadowRelevance = IsShadowCast(View);
|
|
|
|
|
Result.bDynamicRelevance = true;
|
|
|
|
|
MaterialRelevance.SetPrimitiveViewRelevance(Result);
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FGeometryCacheSceneProxy::CanBeOccluded() const
|
|
|
|
|
{
|
|
|
|
|
return !MaterialRelevance.bDisableDepthTest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32 FGeometryCacheSceneProxy::GetMemoryFootprint(void) const
|
|
|
|
|
{
|
|
|
|
|
return(sizeof(*this) + GetAllocatedSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32 FGeometryCacheSceneProxy::GetAllocatedSize(void) const
|
|
|
|
|
{
|
|
|
|
|
return(FPrimitiveSceneProxy::GetAllocatedSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeometryCacheSceneProxy::UpdateSectionWorldMatrix(const int32 SectionIndex, const FMatrix& WorldMatrix)
|
|
|
|
|
{
|
|
|
|
|
check(SectionIndex < Sections.Num() && "Section Index out of range");
|
|
|
|
|
Sections[SectionIndex]->WorldMatrix = WorldMatrix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FGeometryCacheSceneProxy::UpdateSectionVertexBuffer(const int32 SectionIndex, FGeometryCacheMeshData* MeshData)
|
|
|
|
|
{
|
|
|
|
|
check(SectionIndex < Sections.Num() && "Section Index out of range");
|
|
|
|
|
check(IsInRenderingThread());
|
|
|
|
|
|
|
|
|
|
Sections[SectionIndex]->MeshData = MeshData;
|
|
|
|
|
|
|
|
|
|
const bool bRecreate = Sections[SectionIndex]->VertexBuffer.Vertices.Num() != Sections[SectionIndex]->MeshData->Vertices.Num();
|
|
|
|
|
Sections[SectionIndex]->VertexBuffer.Vertices.Empty(Sections[SectionIndex]->MeshData->Vertices.Num());
|
|
|
|
|
Sections[SectionIndex]->VertexBuffer.Vertices.Append(Sections[SectionIndex]->MeshData->Vertices);
|
|
|
|
|
|
|
|
|
|
if (bRecreate)
|
|
|
|
|
{
|
|
|
|
|
Sections[SectionIndex]->VertexBuffer.InitRHI();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Sections[SectionIndex]->VertexBuffer.UpdateRHI();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeometryCacheSceneProxy::UpdateSectionIndexBuffer(const int32 SectionIndex, const TArray<int32>& Indices)
|
|
|
|
|
{
|
|
|
|
|
check(SectionIndex < Sections.Num() && "Section Index out of range");
|
|
|
|
|
check(IsInRenderingThread());
|
|
|
|
|
|
|
|
|
|
const bool bRecreate = Sections[SectionIndex]->IndexBuffer.Indices.Num() != Indices.Num();
|
|
|
|
|
|
|
|
|
|
Sections[SectionIndex]->IndexBuffer.Indices.Empty(Indices.Num());
|
|
|
|
|
Sections[SectionIndex]->IndexBuffer.Indices.Append(Indices);
|
|
|
|
|
if (bRecreate)
|
|
|
|
|
{
|
|
|
|
|
Sections[SectionIndex]->IndexBuffer.InitRHI();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Sections[SectionIndex]->IndexBuffer.UpdateRHI();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeometryCacheSceneProxy::ClearSections()
|
|
|
|
|
{
|
|
|
|
|
Sections.Empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGeomCacheVertexFactory::FGeomCacheVertexFactory()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheVertexFactory::Init_RenderThread(const FGeomCacheVertexBuffer* VertexBuffer)
|
|
|
|
|
{
|
|
|
|
|
check(IsInRenderingThread());
|
|
|
|
|
|
|
|
|
|
// Initialize the vertex factory's stream components.
|
|
|
|
|
DataType NewData;
|
|
|
|
|
NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Position, VET_Float3);
|
|
|
|
|
NewData.TextureCoordinates.Add(
|
|
|
|
|
FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2)
|
|
|
|
|
);
|
|
|
|
|
NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentX, VET_PackedNormal);
|
|
|
|
|
NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentZ, VET_PackedNormal);
|
|
|
|
|
NewData.ColorComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Color, VET_Color);
|
|
|
|
|
SetData(NewData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheVertexFactory::Init(const FGeomCacheVertexBuffer* VertexBuffer)
|
|
|
|
|
{
|
|
|
|
|
if (IsInRenderingThread())
|
|
|
|
|
{
|
|
|
|
|
Init_RenderThread(VertexBuffer);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
|
|
|
|
|
InitGeomCacheVertexFactory,
|
|
|
|
|
FGeomCacheVertexFactory*, VertexFactory, this,
|
|
|
|
|
const FGeomCacheVertexBuffer*, VertexBuffer, VertexBuffer,
|
|
|
|
|
{
|
|
|
|
|
VertexFactory->Init_RenderThread(VertexBuffer);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheIndexBuffer::InitRHI()
|
|
|
|
|
{
|
|
|
|
|
FRHIResourceCreateInfo CreateInfo;
|
2015-06-30 14:18:55 -04:00
|
|
|
void* Buffer = nullptr;
|
2015-06-30 14:36:13 -04:00
|
|
|
IndexBufferRHI = RHICreateAndLockIndexBuffer(sizeof(int32), Indices.Num() * sizeof(int32), BUF_Static, CreateInfo, Buffer);
|
2015-06-18 06:59:14 -04:00
|
|
|
|
2015-06-30 14:18:55 -04:00
|
|
|
// Write the indices to the index buffer.
|
2015-06-18 06:59:14 -04:00
|
|
|
FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(int32));
|
|
|
|
|
RHIUnlockIndexBuffer(IndexBufferRHI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheIndexBuffer::UpdateRHI()
|
|
|
|
|
{
|
|
|
|
|
// Copy the index data into the index buffer.
|
|
|
|
|
void* Buffer = RHILockIndexBuffer(IndexBufferRHI, 0, Indices.Num() * sizeof(int32), RLM_WriteOnly);
|
|
|
|
|
FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(int32));
|
|
|
|
|
RHIUnlockIndexBuffer(IndexBufferRHI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheVertexBuffer::InitRHI()
|
|
|
|
|
{
|
|
|
|
|
const uint32 SizeInBytes = Vertices.Num() * sizeof(FDynamicMeshVertex);
|
|
|
|
|
|
|
|
|
|
FGeomCacheVertexResourceArray ResourceArray(Vertices.GetData(), SizeInBytes);
|
|
|
|
|
FRHIResourceCreateInfo CreateInfo(&ResourceArray);
|
|
|
|
|
VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Static, CreateInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FGeomCacheVertexBuffer::UpdateRHI()
|
|
|
|
|
{
|
|
|
|
|
// Copy the vertex data into the vertex buffer.
|
|
|
|
|
void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly);
|
|
|
|
|
FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex));
|
|
|
|
|
RHIUnlockVertexBuffer(VertexBufferRHI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGeomCacheVertexResourceArray::FGeomCacheVertexResourceArray(void* InData, uint32 InSize) : Data(InData)
|
|
|
|
|
, Size(InSize)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const void* FGeomCacheVertexResourceArray::GetResourceData() const
|
|
|
|
|
{
|
|
|
|
|
return Data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32 FGeomCacheVertexResourceArray::GetResourceDataSize() const
|
|
|
|
|
{
|
|
|
|
|
return Size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheVertexResourceArray::Discard()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FGeomCacheVertexResourceArray::IsStatic() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FGeomCacheVertexResourceArray::GetAllowCPUAccess() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeomCacheVertexResourceArray::SetAllowCPUAccess(bool bInNeedsCPUAccess)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|