// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "SceneViewExtension.h" #include "WaterInfoRendering.h" #include "Misc/ScopeLock.h" class AWaterZone; class FWaterMeshSceneProxy; class FWaterViewExtension : public FWorldSceneViewExtension { public: FWaterViewExtension(const FAutoRegister& AutoReg, UWorld* InWorld); ~FWaterViewExtension(); void Initialize(); void Deinitialize(); // FSceneViewExtensionBase implementation : virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override; virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override; virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override; virtual void PreRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& InViewFamily) override; virtual void PreRenderView_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView) override; virtual void PreRenderBasePass_RenderThread(FRDGBuilder& GraphBuilder, bool bDepthBufferIsPopulated) override; // End FSceneViewExtensionBase implementation WATER_API void MarkWaterInfoTextureForRebuild(const UE::WaterInfo::FRenderingContext& RenderContext); WATER_API void MarkGPUDataDirty(); WATER_API void AddWaterZone(AWaterZone* InWaterZone); WATER_API void RemoveWaterZone(AWaterZone* InWaterZone); WATER_API bool GetZoneLocation(const AWaterZone* InWaterZone, int32 PlayerIndex, FVector& OutLocation) const; void CreateSceneProxyQuadtrees(FWaterMeshSceneProxy* SceneProxy); struct FWaterZoneInfo { UE::WaterInfo::FRenderingContext RenderContext; /** * For each water zone, per view: store the bounds of the tile from which the water zone was last rendered. * When the view location crosses the bounds, submit a new update to reflect the new active area */ struct FWaterZoneViewInfo { TOptional UpdateBounds = FBox2D(ForceInit); FVector Center = FVector(ForceInit); FWaterMeshSceneProxy* OldSceneProxy = nullptr; // bIsDirty is used to force water info texture update for this WaterZone bool bIsDirty = true; // bShouldUpdateQuadtree is set to true when the water info texture is update, // to make sure the quadtree for this WaterZone is also updated bool bShouldUpdateQuadtree = false; }; TArray> ViewInfos; }; const TWeakObjectPtrKeyMap& GetWaterZoneInfos() const { return WaterZoneInfos; }; private: int32 CurrentNumViews = 0; TWeakObjectPtrKeyMap WaterZoneInfos; struct FWaterGPUResources { FBufferRHIRef WaterBodyDataBuffer; FShaderResourceViewRHIRef WaterBodyDataSRV; FBufferRHIRef AuxDataBuffer; FShaderResourceViewRHIRef AuxDataSRV; }; TSharedRef WaterGPUData; TArray> ViewPlayerIndices; TMap NonDataViewsQuadtreeKeys; bool bWaterInfoTextureRebuildPending = true; bool bRebuildGPUData = true; bool bRequestForcedBoundsUpdate = false; bool bForceBoundsUpdate = false; // this flag lets us know if we can skip looping through water zones for quadtrees updates, as an optimization bool bAnyQuadTreeUpdateRequired = false; // store the locations of every active water mesh scene proxy quad tree based on the key TMap QuadTreeKeyLocationMap; void UpdateGPUBuffers(); void UpdateViewInfo(AWaterZone* WaterZone, const FSceneView& InView); void RenderWaterInfoTexture(FSceneViewFamily& InViewFamily, FSceneView& InView, const FWaterZoneInfo* WaterZoneInfo, FSceneInterface* Scene, const FVector& ZoneCenter); // Returns the index in the views array corresponding to InView's PlayerIndex. If the index is not found it adds a new entry. int32 GetOrAddViewindex(const FSceneView& InView); // Returns the index in the views array corresponding to InView's PlayerIndex. INDEX_NONE if it doesn't find it int32 GetViewIndex(int32 PlayerIndex) const; int32 GetViewIndex(const FSceneView& InView) const; bool ShouldHaveWaterZoneViewData(const FSceneView& InView) const; void DrawDebugInfo(const FSceneView& InView, AWaterZone* WaterZone); void OnWorldDestroyed(UWorld* InWorld); }; struct FWaterMeshGPUWork { struct FCallback { class FWaterMeshSceneProxy* Proxy = nullptr; TFunction Function; }; TArray Callbacks; }; extern FWaterMeshGPUWork GWaterMeshGPUWork;