From e5f0e05d43f3359cd5fdf1eaaab7096b93ca6103 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 23 Aug 2024 00:00:42 +0200 Subject: [PATCH] Fix terrain rendering to use the same LOD for main view and shadow passes #2555 #2256 --- .../CustomEditors/Dedicated/TerrainEditor.cs | 5 +- Source/Engine/Terrain/Terrain.cpp | 82 +++++++++++++------ Source/Engine/Terrain/Terrain.h | 4 +- Source/Engine/Terrain/TerrainChunk.h | 6 +- 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/TerrainEditor.cs b/Source/Editor/CustomEditors/Dedicated/TerrainEditor.cs index 30ffb6866..8aaf5b7d6 100644 --- a/Source/Editor/CustomEditors/Dedicated/TerrainEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/TerrainEditor.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. +using FlaxEditor.Utilities; using FlaxEngine; namespace FlaxEditor.CustomEditors.Dedicated @@ -29,8 +30,8 @@ namespace FlaxEditor.CustomEditors.Dedicated chunkSize, 1.0f / (resolution.X + 1e-9f), 1.0f / (resolution.Z + 1e-9f), - totalSize.X * 0.00001f, - totalSize.Z * 0.00001f + totalSize.X / Units.Meters2Units * 0.001f, + totalSize.Z / Units.Meters2Units * 0.001f ); var label = layout.Label(text); label.Label.AutoHeight = true; diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index 66ecbd377..d0b9e532f 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -291,7 +291,7 @@ void Terrain::SetPhysicalMaterials(const Array drawnChunks; + for (RenderContext& renderContext : renderContextBatch.Contexts) + { + const DrawPass drawModes = DrawModes & renderContext.View.Pass; + if (drawModes == DrawPass::None) + continue; + DrawImpl(renderContext, drawnChunks); + } +} + void Terrain::Draw(RenderContext& renderContext) { const DrawPass drawModes = DrawModes & renderContext.View.Pass; if (drawModes == DrawPass::None) return; PROFILE_CPU(); - if (renderContext.View.Pass == DrawPass::GlobalSDF) + if (DrawSetup(renderContext)) + return; + HashSet drawnChunks; + DrawImpl(renderContext, drawnChunks); +} + +bool Terrain::DrawSetup(RenderContext& renderContext) +{ + // Special drawing modes + const DrawPass drawModes = DrawModes & renderContext.View.Pass; + if (drawModes == DrawPass::GlobalSDF) { - if ((DrawModes & DrawPass::GlobalSDF) == DrawPass::None) - return; const float chunkSize = TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize; const float posToUV = 0.25f / chunkSize; Float4 localToUV(posToUV, posToUV, 0.0f, 0.0f); @@ -533,12 +556,10 @@ void Terrain::Draw(RenderContext& renderContext) patchTransform = _transform.LocalToWorld(patchTransform); GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, patch->Heightmap->GetTexture(), patchTransform, patch->_bounds, localToUV); } - return; + return true; } - if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas) + if (drawModes == DrawPass::GlobalSurfaceAtlas) { - if ((DrawModes & DrawPass::GlobalSurfaceAtlas) == DrawPass::None) - return; for (TerrainPatch* patch : _patches) { if (!patch->Heightmap) @@ -556,11 +577,27 @@ void Terrain::Draw(RenderContext& renderContext) GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, chunk, chunkSphere, chunk->GetTransform(), localBounds, 1 << 2, false); } } - return; + return true; } + // Reset cached LOD for chunks (prevent LOD transition from invisible chunks) + for (int32 patchIndex = 0; patchIndex < _patches.Count(); patchIndex++) + { + const auto patch = _patches[patchIndex]; + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) + { + auto chunk = &patch->Chunks[chunkIndex]; + chunk->_cachedDrawLOD = 0; + } + } + + return false; +} + +void Terrain::DrawImpl(RenderContext& renderContext, HashSet& drawnChunks) +{ // Collect chunks to render and calculate LOD/material for them (required to be done before to gather NeighborLOD) - _drawChunks.Clear(); + Array drawChunks; // Frustum vs Box culling for patches const BoundingFrustum frustum = renderContext.View.CullingFrustum; @@ -579,33 +616,24 @@ void Terrain::Draw(RenderContext& renderContext) for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto chunk = &patch->Chunks[chunkIndex]; - chunk->_cachedDrawLOD = 0; bounds = BoundingBox(chunk->_bounds.Minimum - origin, chunk->_bounds.Maximum - origin); if (renderContext.View.IsCullingDisabled || frustum.Intersects(bounds)) { - if (chunk->PrepareDraw(renderContext)) - { - // Add chunk for drawing - _drawChunks.Add(chunk); - } + if (!drawnChunks.Contains(chunk) && !chunk->PrepareDraw(renderContext)) + continue; + + // Add chunk for drawing + drawChunks.Add(chunk); + drawnChunks.Add(chunk); } } } - else - { - // Reset cached LOD for chunks (prevent LOD transition from invisible chunks) - for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) - { - auto chunk = &patch->Chunks[chunkIndex]; - chunk->_cachedDrawLOD = 0; - } - } } // Draw all visible chunks - for (int32 i = 0; i < _drawChunks.Count(); i++) + for (int32 i = 0; i < drawChunks.Count(); i++) { - _drawChunks.Get()[i]->Draw(renderContext); + drawChunks.Get()[i]->Draw(renderContext); } } diff --git a/Source/Engine/Terrain/Terrain.h b/Source/Engine/Terrain/Terrain.h index 17f4bdccd..d9ef89fb5 100644 --- a/Source/Engine/Terrain/Terrain.h +++ b/Source/Engine/Terrain/Terrain.h @@ -72,7 +72,6 @@ private: Vector3 _boundsExtent; Float3 _cachedScale; Array> _patches; - Array _drawChunks; Array, FixedAllocation<8>> _physicalMaterials; public: @@ -424,9 +423,12 @@ private: #if TERRAIN_USE_PHYSICS_DEBUG void DrawPhysicsDebug(RenderView& view); #endif + bool DrawSetup(RenderContext& renderContext); + void DrawImpl(RenderContext& renderContext, HashSet& drawnChunks); public: // [PhysicsColliderActor] + void Draw(RenderContextBatch& renderContextBatch) override; void Draw(RenderContext& renderContext) override; #if USE_EDITOR void OnDebugDrawSelected() override; diff --git a/Source/Engine/Terrain/TerrainChunk.h b/Source/Engine/Terrain/TerrainChunk.h index f73303ae1..b4d70ec6d 100644 --- a/Source/Engine/Terrain/TerrainChunk.h +++ b/Source/Engine/Terrain/TerrainChunk.h @@ -34,9 +34,9 @@ private: float _perInstanceRandom; float _yOffset, _yHeight; - TerrainChunk* _neighbors[4]; - byte _cachedDrawLOD; - IMaterial* _cachedDrawMaterial; + TerrainChunk* _neighbors[4] = {}; + byte _cachedDrawLOD = 0; + IMaterial* _cachedDrawMaterial = nullptr; void Init(TerrainPatch* patch, uint16 x, uint16 z);