// 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>& OutTargetLayerGroups) const { using namespace UE::Landscape::EditLayers; // Supports all heightmaps and weightmaps: OutSupportedTargetTypeState = FEditLayerTargetTypeState(InMergeContext, ELandscapeToolTargetTypeFlags::All, InMergeContext->GetValidTargetLayerBitIndices()); OutEnabledTargetTypeState = OutSupportedTargetTypeState; } TArray 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>& OutTargetLayerGroups) const { // Only relevant for heightmaps : OutSupportedTargetTypeState.SetTargetTypeMask(ELandscapeToolTargetTypeFlags::Heightmap); OutEnabledTargetTypeState.SetTargetTypeMask(ELandscapeToolTargetTypeFlags::Heightmap); } TArray 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>& 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 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