Files
UnrealEngine/Engine/Source/Runtime/Landscape/Private/LandscapeEditLayerRendererPrivate.cpp
2025-05-18 13:04:45 +08:00

160 lines
8.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LandscapeEditLayerRendererPrivate.h"
#include "Algo/AllOf.h"
#include "Algo/ForEach.h"
#include "Algo/Transform.h"
#include "LandscapeEditResourcesSubsystem.h"
#include "LandscapeEditLayerMergeRenderContext.h"
#include "LandscapeLayerInfoObject.h"
#include "LandscapeInfo.h"
#include "RHIAccess.h"
#if WITH_EDITOR
// ----------------------------------------------------------------------------------
void ULandscapeDefaultEditLayerRenderer::GetRendererStateInfo(const UE::Landscape::EditLayers::FMergeContext* InMergeContext,
UE::Landscape::EditLayers::FEditLayerTargetTypeState& OutSupportedTargetTypeState, UE::Landscape::EditLayers::FEditLayerTargetTypeState& OutEnabledTargetTypeState, TArray<TBitArray<>>& OutTargetLayerGroups) const
{
using namespace UE::Landscape::EditLayers;
// Supports all heightmaps and weightmaps:
OutSupportedTargetTypeState = FEditLayerTargetTypeState(InMergeContext, ELandscapeToolTargetTypeFlags::All, InMergeContext->GetValidTargetLayerBitIndices());
OutEnabledTargetTypeState = OutSupportedTargetTypeState;
}
TArray<UE::Landscape::EditLayers::FEditLayerRenderItem> ULandscapeDefaultEditLayerRenderer::GetRenderItems(const UE::Landscape::EditLayers::FMergeContext* InMergeContext) const
{
using namespace UE::Landscape::EditLayers;
FEditLayerTargetTypeState OutputTargetTypeState(InMergeContext, ELandscapeToolTargetTypeFlags::All, InMergeContext->GetValidTargetLayerBitIndices());
// Standard renderer : we don't need more than the component itself to render properly:
FInputWorldArea InputWorldArea(FInputWorldArea::CreateLocalComponent());
// The renderer only writes into the component itself (i.e. it renders to the area that it's currently being asked to render to):
FOutputWorldArea OutputWorldArea(FOutputWorldArea::CreateLocalComponent());
// The renderer is only providing default data for existing weightmaps so it doesn't generate new ones, hence we pass bModifyExistingWeightmapsOnly to true :
return { FEditLayerRenderItem(OutputTargetTypeState, InputWorldArea, OutputWorldArea, /*bModifyExistingWeightmapsOnly = */true) };
}
FString ULandscapeDefaultEditLayerRenderer::GetEditLayerRendererDebugName() const
{
return TEXT("Default");
}
bool ULandscapeDefaultEditLayerRenderer::RenderLayer(UE::Landscape::EditLayers::FRenderParams& RenderParams, UE::Landscape::FRDGBuilderRecorder& RDGBuilderRecorder)
{
using namespace UE::Landscape::EditLayers;
checkf(RDGBuilderRecorder.IsRecording(), TEXT("ERenderFlags::RenderMode_Recorded means the command recorder should be recording at this point"));
FMergeRenderContext* RenderContext = RenderParams.MergeRenderContext;
RenderContext->CycleBlendRenderTargets(RDGBuilderRecorder);
ULandscapeScratchRenderTarget* WriteRT = RenderContext->GetBlendRenderTargetWrite();
// Start from a blank canvas so that the first layer is blended with nothing underneath :
WriteRT->Clear(RDGBuilderRecorder);
check(WriteRT->GetCurrentState() == ERHIAccess::RTV);
// Render the components of the batch for each target layer into the "pseudo-stencil" buffer, so that it can be sampled by users as a UTextures in UMaterials and such :
RenderContext->RenderValidityRenderTargets(RDGBuilderRecorder);
return true;
}
// ----------------------------------------------------------------------------------
void ULandscapeHeightmapNormalsEditLayerRenderer::GetRendererStateInfo(const UE::Landscape::EditLayers::FMergeContext* InMergeContext,
UE::Landscape::EditLayers::FEditLayerTargetTypeState& OutSupportedTargetTypeState, UE::Landscape::EditLayers::FEditLayerTargetTypeState& OutEnabledTargetTypeState, TArray<TBitArray<>>& OutTargetLayerGroups) const
{
// Only relevant for heightmaps :
OutSupportedTargetTypeState.SetTargetTypeMask(ELandscapeToolTargetTypeFlags::Heightmap);
OutEnabledTargetTypeState.SetTargetTypeMask(ELandscapeToolTargetTypeFlags::Heightmap);
}
TArray<UE::Landscape::EditLayers::FEditLayerRenderItem> ULandscapeHeightmapNormalsEditLayerRenderer::GetRenderItems(const UE::Landscape::EditLayers::FMergeContext* InMergeContext) const
{
using namespace UE::Landscape::EditLayers;
// Only relevant for heightmaps :
if (!InMergeContext->IsHeightmapMerge())
{
return {};
}
FEditLayerTargetTypeState OutputTargetTypeState(InMergeContext, ELandscapeToolTargetTypeFlags::Heightmap);
// The input is relative and its size is equal to the size of 3x3 landscape components so that we gather all neighbor landscape components around each component :
FInputWorldArea InputWorldArea(FInputWorldArea::CreateLocalComponent(FIntRect(-1, -1, 1, 1)));
// The renderer only writes into the component itself (i.e. it renders to the area that it's currently being asked to render to):
FOutputWorldArea OutputWorldArea(FOutputWorldArea::CreateLocalComponent());
return { FEditLayerRenderItem(OutputTargetTypeState, InputWorldArea, OutputWorldArea, /*bModifyExistingWeightmapsOnly = */false) };
}
FString ULandscapeHeightmapNormalsEditLayerRenderer::GetEditLayerRendererDebugName() const
{
return TEXT("Normals");
}
// ----------------------------------------------------------------------------------
void ULandscapeWeightmapWeightBlendedLayersRenderer::GetRendererStateInfo(const UE::Landscape::EditLayers::FMergeContext* InMergeContext,
UE::Landscape::EditLayers::FEditLayerTargetTypeState& OutSupportedTargetTypeState, UE::Landscape::EditLayers::FEditLayerTargetTypeState& OutEnabledTargetTypeState, TArray<TBitArray<>>& OutTargetLayerGroups) const
{
using namespace UE::Landscape::EditLayers;
TBitArray<> WeightBlendedWeightmapLayerBitIndices = GatherWeightBlendedWeightmapLayerBitIndices(InMergeContext);
// Only relevant for weightmaps :
FEditLayerTargetTypeState OutputTargetTypeState(InMergeContext, ELandscapeToolTargetTypeFlags::Weightmap, WeightBlendedWeightmapLayerBitIndices);
OutEnabledTargetTypeState = OutSupportedTargetTypeState = OutputTargetTypeState;
// Now fill in the target layer groups : one group for all weight-blended layers :
if (WeightBlendedWeightmapLayerBitIndices.Contains(true))
{
OutTargetLayerGroups.Add(WeightBlendedWeightmapLayerBitIndices);
}
}
TArray<UE::Landscape::EditLayers::FEditLayerRenderItem> ULandscapeWeightmapWeightBlendedLayersRenderer::GetRenderItems(const UE::Landscape::EditLayers::FMergeContext* InMergeContext) const
{
using namespace UE::Landscape::EditLayers;
// Only relevant for weightmaps :
if (InMergeContext->IsHeightmapMerge())
{
return {};
}
TBitArray<> WeightBlendedWeightmapLayerBitIndices = GatherWeightBlendedWeightmapLayerBitIndices(InMergeContext);
FEditLayerTargetTypeState OutputTargetTypeState(InMergeContext, ELandscapeToolTargetTypeFlags::Weightmap, WeightBlendedWeightmapLayerBitIndices);
// Standard renderer : we don't need more than the component itself to render properly:
FInputWorldArea InputWorldArea(FInputWorldArea::CreateLocalComponent());
// The renderer only writes into the component itself (i.e. it renders to the area that it's currently being asked to render to):
FOutputWorldArea OutputWorldArea(FOutputWorldArea::CreateLocalComponent());
// The renderer is only blending existing weightmaps so it doesn't generate new ones, hence we pass bModifyExistingWeightmapsOnly to true :
return { FEditLayerRenderItem(OutputTargetTypeState, InputWorldArea, OutputWorldArea, /*bModifyExistingWeightmapsOnly = */true) };
}
FString ULandscapeWeightmapWeightBlendedLayersRenderer::GetEditLayerRendererDebugName() const
{
return TEXT("Final Weight Blend");
}
TBitArray<> ULandscapeWeightmapWeightBlendedLayersRenderer::GatherWeightBlendedWeightmapLayerBitIndices(const UE::Landscape::EditLayers::FMergeContext* InMergeContext) const
{
TBitArray<> WeightBlendedWeightmapLayerBitIndices = InMergeContext->GetValidTargetLayerBitIndices();
InMergeContext->ForEachValidTargetLayer(
[&WeightBlendedWeightmapLayerBitIndices, InMergeContext] (int32 InTargetLayerIndex, const FName& InTargetLayerName, ULandscapeLayerInfoObject* InWeightmapLayerInfo)
{
check(InWeightmapLayerInfo != nullptr);
WeightBlendedWeightmapLayerBitIndices[InTargetLayerIndex] = !InWeightmapLayerInfo->bNoWeightBlend;
return true;
});
return WeightBlendedWeightmapLayerBitIndices;
}
#endif // WITH_EDITOR