Merge remote-tracking branch 'origin/master' into 1.9
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using FlaxEditor.Utilities;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
namespace FlaxEditor.CustomEditors.Dedicated
|
namespace FlaxEditor.CustomEditors.Dedicated
|
||||||
@@ -29,8 +30,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
chunkSize,
|
chunkSize,
|
||||||
1.0f / (resolution.X + 1e-9f),
|
1.0f / (resolution.X + 1e-9f),
|
||||||
1.0f / (resolution.Z + 1e-9f),
|
1.0f / (resolution.Z + 1e-9f),
|
||||||
totalSize.X * 0.00001f,
|
totalSize.X / Units.Meters2Units * 0.001f,
|
||||||
totalSize.Z * 0.00001f
|
totalSize.Z / Units.Meters2Units * 0.001f
|
||||||
);
|
);
|
||||||
var label = layout.Label(text);
|
var label = layout.Label(text);
|
||||||
label.Label.AutoHeight = true;
|
label.Label.AutoHeight = true;
|
||||||
|
|||||||
@@ -602,3 +602,13 @@ bool ManagedEditor::CreateAsset(const String& tag, String outputPath)
|
|||||||
FileSystem::NormalizePath(outputPath);
|
FileSystem::NormalizePath(outputPath);
|
||||||
return AssetsImportingManager::Create(tag, outputPath);
|
return AssetsImportingManager::Create(tag, outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array<Guid> ManagedEditor::GetAssetReferences(const Guid& assetId)
|
||||||
|
{
|
||||||
|
Array<Guid> result;
|
||||||
|
if (auto* asset = Content::Load<Asset>(assetId))
|
||||||
|
{
|
||||||
|
asset->GetReferences(result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -218,6 +218,13 @@ public:
|
|||||||
/// <param name="outputPath">Output asset path.</param>
|
/// <param name="outputPath">Output asset path.</param>
|
||||||
API_FUNCTION() static bool CreateAsset(const String& tag, String outputPath);
|
API_FUNCTION() static bool CreateAsset(const String& tag, String outputPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of asset references of a given asset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assetId">The asset ID.</param>
|
||||||
|
/// <returns>List of referenced assets.</returns>
|
||||||
|
API_FUNCTION() static Array<Guid> GetAssetReferences(const Guid& assetId);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
|
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
namespace FlaxEditor.SceneGraph.Actors
|
namespace FlaxEditor.SceneGraph.Actors
|
||||||
@@ -10,6 +14,15 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
public sealed class TerrainNode : ActorNode
|
public sealed class TerrainNode : ActorNode
|
||||||
{
|
{
|
||||||
|
private struct RemovedTerrain
|
||||||
|
{
|
||||||
|
public Guid SceneId;
|
||||||
|
public Guid TerrainId;
|
||||||
|
public string[] Files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<RemovedTerrain> _cleanupFiles;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TerrainNode(Actor actor)
|
public TerrainNode(Actor actor)
|
||||||
: base(actor)
|
: base(actor)
|
||||||
@@ -18,5 +31,68 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool AffectsNavigation => true;
|
public override bool AffectsNavigation => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Delete()
|
||||||
|
{
|
||||||
|
// Schedule terrain data files for automatic cleanup
|
||||||
|
if (_cleanupFiles == null)
|
||||||
|
{
|
||||||
|
_cleanupFiles = new List<RemovedTerrain>();
|
||||||
|
Engine.RequestingExit += OnRequestingExit;
|
||||||
|
}
|
||||||
|
if (Actor is Terrain terrain)
|
||||||
|
{
|
||||||
|
var removed = new RemovedTerrain
|
||||||
|
{
|
||||||
|
SceneId = terrain.Scene?.ID ?? Guid.Empty,
|
||||||
|
TerrainId = terrain.ID,
|
||||||
|
Files = new string[4],
|
||||||
|
};
|
||||||
|
for (int i = 0; i < terrain.PatchesCount; i++)
|
||||||
|
{
|
||||||
|
var patch = terrain.GetPatch(i);
|
||||||
|
if (patch.Heightmap)
|
||||||
|
removed.Files[0] = patch.Heightmap.Path;
|
||||||
|
if (patch.Heightfield)
|
||||||
|
removed.Files[1] = patch.Heightfield.Path;
|
||||||
|
if (patch.GetSplatmap(0))
|
||||||
|
removed.Files[2] = patch.GetSplatmap(0).Path;
|
||||||
|
if (patch.GetSplatmap(1))
|
||||||
|
removed.Files[3] = patch.GetSplatmap(1).Path;
|
||||||
|
}
|
||||||
|
_cleanupFiles.Add(removed);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRequestingExit()
|
||||||
|
{
|
||||||
|
foreach (var e in _cleanupFiles)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Skip removing this terrain file sif it's still referenced
|
||||||
|
var sceneReferences = Editor.GetAssetReferences(e.SceneId);
|
||||||
|
if (sceneReferences != null && sceneReferences.Contains(e.TerrainId))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Delete files
|
||||||
|
foreach (var file in e.Files)
|
||||||
|
{
|
||||||
|
if (file != null && File.Exists(file))
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Editor.LogWarning(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_cleanupFiles.Clear();
|
||||||
|
_cleanupFiles = null;
|
||||||
|
Engine.RequestingExit -= OnRequestingExit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void SceneAnimationPlayer::Pause()
|
|||||||
if (_state != PlayState::Playing)
|
if (_state != PlayState::Playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IsActiveInHierarchy() && _state == PlayState::Playing)
|
if (IsActiveInHierarchy())
|
||||||
{
|
{
|
||||||
UNREGISTER_TICK;
|
UNREGISTER_TICK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1027,6 +1027,13 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iterator& operator=(Iterator&& v)
|
||||||
|
{
|
||||||
|
_array = v._array;
|
||||||
|
_index = v._index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Iterator& operator++()
|
Iterator& operator++()
|
||||||
{
|
{
|
||||||
if (_index != _array->_count)
|
if (_index != _array->_count)
|
||||||
|
|||||||
@@ -173,6 +173,14 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iterator& operator=(Iterator&& v)
|
||||||
|
{
|
||||||
|
_collection = v._collection;
|
||||||
|
_chunkIndex = v._chunkIndex;
|
||||||
|
_index = v._index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Iterator& operator++()
|
Iterator& operator++()
|
||||||
{
|
{
|
||||||
// Check if it is not at end
|
// Check if it is not at end
|
||||||
|
|||||||
@@ -348,6 +348,13 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iterator& operator=(Iterator&& v)
|
||||||
|
{
|
||||||
|
_collection = v._collection;
|
||||||
|
_index = v._index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Iterator& operator++()
|
Iterator& operator++()
|
||||||
{
|
{
|
||||||
const int32 capacity = _collection->_size;
|
const int32 capacity = _collection->_size;
|
||||||
|
|||||||
@@ -329,6 +329,13 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iterator& operator=(Iterator&& v)
|
||||||
|
{
|
||||||
|
_collection = v._collection;
|
||||||
|
_index = v._index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Iterator& operator++()
|
Iterator& operator++()
|
||||||
{
|
{
|
||||||
const int32 capacity = _collection->_size;
|
const int32 capacity = _collection->_size;
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ public:
|
|||||||
Platform::MemoryCopy(Base::_data, prev, prevLength * sizeof(T));
|
Platform::MemoryCopy(Base::_data, prev, prevLength * sizeof(T));
|
||||||
Platform::MemoryCopy(Base::_data + prevLength * sizeof(T), data, length * sizeof(T));
|
Platform::MemoryCopy(Base::_data + prevLength * sizeof(T), data, length * sizeof(T));
|
||||||
|
|
||||||
if (_isAllocated && prev)
|
if (_isAllocated)
|
||||||
Allocator::Free(prev);
|
Allocator::Free(prev);
|
||||||
_isAllocated = true;
|
_isAllocated = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ protected:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringViewBase(const StringViewBase& other)
|
||||||
|
: _data(other._data)
|
||||||
|
, _length(other._length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef T CharType;
|
typedef T CharType;
|
||||||
|
|
||||||
|
|||||||
@@ -133,9 +133,10 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan
|
|||||||
void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, const FoliageType& type, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const
|
void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, const FoliageType& type, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const
|
||||||
{
|
{
|
||||||
// Skip clusters that around too far from view
|
// Skip clusters that around too far from view
|
||||||
const Vector3 viewOrigin = renderContext.View.Origin;
|
const auto lodView = (renderContext.LodProxyView ? renderContext.LodProxyView : &renderContext.View);
|
||||||
if (Float3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center - viewOrigin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
|
if (Float3::Distance(lodView->Position, cluster->TotalBoundsSphere.Center - lodView->Origin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
|
||||||
return;
|
return;
|
||||||
|
const Vector3 viewOrigin = renderContext.View.Origin;
|
||||||
|
|
||||||
//DebugDraw::DrawBox(cluster->Bounds, Color::Red);
|
//DebugDraw::DrawBox(cluster->Bounds, Color::Red);
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
|
|||||||
auto& instance = *cluster->Instances.Get()[i];
|
auto& instance = *cluster->Instances.Get()[i];
|
||||||
BoundingSphere sphere = instance.Bounds;
|
BoundingSphere sphere = instance.Bounds;
|
||||||
sphere.Center -= viewOrigin;
|
sphere.Center -= viewOrigin;
|
||||||
if (Float3::Distance(renderContext.View.Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance &&
|
if (Float3::Distance(lodView->Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance &&
|
||||||
renderContext.View.CullingFrustum.Intersects(sphere))
|
renderContext.View.CullingFrustum.Intersects(sphere))
|
||||||
{
|
{
|
||||||
const auto modelFrame = instance.DrawState.PrevFrame + 1;
|
const auto modelFrame = instance.DrawState.PrevFrame + 1;
|
||||||
@@ -262,9 +263,10 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
|
|||||||
void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, Mesh::DrawInfo& draw)
|
void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, Mesh::DrawInfo& draw)
|
||||||
{
|
{
|
||||||
// Skip clusters that around too far from view
|
// Skip clusters that around too far from view
|
||||||
const Vector3 viewOrigin = renderContext.View.Origin;
|
const auto lodView = (renderContext.LodProxyView ? renderContext.LodProxyView : &renderContext.View);
|
||||||
if (Float3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center - viewOrigin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
|
if (Float3::Distance(lodView->Position, cluster->TotalBoundsSphere.Center - lodView->Origin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
|
||||||
return;
|
return;
|
||||||
|
const Vector3 viewOrigin = renderContext.View.Origin;
|
||||||
|
|
||||||
//DebugDraw::DrawBox(cluster->Bounds, Color::Red);
|
//DebugDraw::DrawBox(cluster->Bounds, Color::Red);
|
||||||
|
|
||||||
@@ -300,7 +302,7 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
|
|||||||
|
|
||||||
// Check if can draw this instance
|
// Check if can draw this instance
|
||||||
if (type._canDraw &&
|
if (type._canDraw &&
|
||||||
Float3::Distance(renderContext.View.Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance &&
|
Float3::Distance(lodView->Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance &&
|
||||||
renderContext.View.CullingFrustum.Intersects(sphere))
|
renderContext.View.CullingFrustum.Intersects(sphere))
|
||||||
{
|
{
|
||||||
Matrix world;
|
Matrix world;
|
||||||
|
|||||||
@@ -289,9 +289,9 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
|||||||
// Check if need to setup ribbon modules
|
// Check if need to setup ribbon modules
|
||||||
int32 ribbonModuleIndex = 0;
|
int32 ribbonModuleIndex = 0;
|
||||||
int32 ribbonModulesDrawIndicesPos = 0;
|
int32 ribbonModulesDrawIndicesPos = 0;
|
||||||
int32 ribbonModulesDrawIndicesStart[PARTICLE_EMITTER_MAX_RIBBONS];
|
int32 ribbonModulesDrawIndicesStart[PARTICLE_EMITTER_MAX_RIBBONS] = {};
|
||||||
int32 ribbonModulesDrawIndicesCount[PARTICLE_EMITTER_MAX_RIBBONS];
|
int32 ribbonModulesDrawIndicesCount[PARTICLE_EMITTER_MAX_RIBBONS] = {};
|
||||||
int32 ribbonModulesSegmentCount[PARTICLE_EMITTER_MAX_RIBBONS];
|
int32 ribbonModulesSegmentCount[PARTICLE_EMITTER_MAX_RIBBONS] = {};
|
||||||
if (emitter->Graph.RibbonRenderingModules.HasItems())
|
if (emitter->Graph.RibbonRenderingModules.HasItems())
|
||||||
{
|
{
|
||||||
// Prepare ribbon data
|
// Prepare ribbon data
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ bool CachedPSO::Init(GPUShader* shader, bool useDepth)
|
|||||||
|
|
||||||
// Create pipeline states
|
// Create pipeline states
|
||||||
GPUPipelineState::Description desc = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
GPUPipelineState::Description desc = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||||
desc.DepthEnable = desc.DepthWriteEnable = useDepth;
|
desc.DepthEnable = useDepth;
|
||||||
desc.DepthWriteEnable = false;
|
desc.DepthWriteEnable = false;
|
||||||
desc.DepthClipEnable = false;
|
desc.DepthClipEnable = false;
|
||||||
desc.VS = shader->GetVS("VS");
|
desc.VS = shader->GetVS("VS");
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ struct FLAXENGINE_API ScriptingTypeHandle
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE ScriptingTypeHandle(ScriptingTypeHandle&& other)
|
||||||
|
: Module(other.Module)
|
||||||
|
, TypeIndex(other.TypeIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ScriptingTypeHandle(const ScriptingTypeInitializer& initializer);
|
ScriptingTypeHandle(const ScriptingTypeInitializer& initializer);
|
||||||
|
|
||||||
FORCE_INLINE operator bool() const
|
FORCE_INLINE operator bool() const
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ void Terrain::SetPhysicalMaterials(const Array<JsonAssetReference<PhysicalMateri
|
|||||||
_physicalMaterials = value;
|
_physicalMaterials = value;
|
||||||
_physicalMaterials.Resize(8);
|
_physicalMaterials.Resize(8);
|
||||||
JsonAsset* materials[8];
|
JsonAsset* materials[8];
|
||||||
for (int32 i = 0;i<8;i++)
|
for (int32 i = 0; i < 8; i++)
|
||||||
materials[i] = _physicalMaterials[i];
|
materials[i] = _physicalMaterials[i];
|
||||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||||
{
|
{
|
||||||
@@ -509,16 +509,39 @@ void Terrain::RemovePatch(const Int2& patchCoord)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void Terrain::Draw(RenderContextBatch& renderContextBatch)
|
||||||
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
|
if (DrawSetup(renderContextBatch.GetMainContext()))
|
||||||
|
return;
|
||||||
|
HashSet<TerrainChunk*, RendererAllocation> 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)
|
void Terrain::Draw(RenderContext& renderContext)
|
||||||
{
|
{
|
||||||
const DrawPass drawModes = DrawModes & renderContext.View.Pass;
|
const DrawPass drawModes = DrawModes & renderContext.View.Pass;
|
||||||
if (drawModes == DrawPass::None)
|
if (drawModes == DrawPass::None)
|
||||||
return;
|
return;
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
if (renderContext.View.Pass == DrawPass::GlobalSDF)
|
if (DrawSetup(renderContext))
|
||||||
|
return;
|
||||||
|
HashSet<TerrainChunk*, RendererAllocation> 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 chunkSize = TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize;
|
||||||
const float posToUV = 0.25f / chunkSize;
|
const float posToUV = 0.25f / chunkSize;
|
||||||
Float4 localToUV(posToUV, posToUV, 0.0f, 0.0f);
|
Float4 localToUV(posToUV, posToUV, 0.0f, 0.0f);
|
||||||
@@ -533,12 +556,10 @@ void Terrain::Draw(RenderContext& renderContext)
|
|||||||
patchTransform = _transform.LocalToWorld(patchTransform);
|
patchTransform = _transform.LocalToWorld(patchTransform);
|
||||||
GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, patch->Heightmap->GetTexture(), patchTransform, patch->_bounds, localToUV);
|
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)
|
for (TerrainPatch* patch : _patches)
|
||||||
{
|
{
|
||||||
if (!patch->Heightmap)
|
if (!patch->Heightmap)
|
||||||
@@ -556,11 +577,27 @@ void Terrain::Draw(RenderContext& renderContext)
|
|||||||
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, chunk, chunkSphere, chunk->GetTransform(), localBounds, 1 << 2, false);
|
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<TerrainChunk*, RendererAllocation>& drawnChunks)
|
||||||
|
{
|
||||||
// Collect chunks to render and calculate LOD/material for them (required to be done before to gather NeighborLOD)
|
// Collect chunks to render and calculate LOD/material for them (required to be done before to gather NeighborLOD)
|
||||||
_drawChunks.Clear();
|
Array<TerrainChunk*, RendererAllocation> drawChunks;
|
||||||
|
|
||||||
// Frustum vs Box culling for patches
|
// Frustum vs Box culling for patches
|
||||||
const BoundingFrustum frustum = renderContext.View.CullingFrustum;
|
const BoundingFrustum frustum = renderContext.View.CullingFrustum;
|
||||||
@@ -579,33 +616,24 @@ void Terrain::Draw(RenderContext& renderContext)
|
|||||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
auto chunk = &patch->Chunks[chunkIndex];
|
auto chunk = &patch->Chunks[chunkIndex];
|
||||||
chunk->_cachedDrawLOD = 0;
|
|
||||||
bounds = BoundingBox(chunk->_bounds.Minimum - origin, chunk->_bounds.Maximum - origin);
|
bounds = BoundingBox(chunk->_bounds.Minimum - origin, chunk->_bounds.Maximum - origin);
|
||||||
if (renderContext.View.IsCullingDisabled || frustum.Intersects(bounds))
|
if (renderContext.View.IsCullingDisabled || frustum.Intersects(bounds))
|
||||||
{
|
{
|
||||||
if (chunk->PrepareDraw(renderContext))
|
if (!drawnChunks.Contains(chunk) && !chunk->PrepareDraw(renderContext))
|
||||||
{
|
continue;
|
||||||
// Add chunk for drawing
|
|
||||||
_drawChunks.Add(chunk);
|
// 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
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ private:
|
|||||||
Vector3 _boundsExtent;
|
Vector3 _boundsExtent;
|
||||||
Float3 _cachedScale;
|
Float3 _cachedScale;
|
||||||
Array<TerrainPatch*, InlinedAllocation<64>> _patches;
|
Array<TerrainPatch*, InlinedAllocation<64>> _patches;
|
||||||
Array<TerrainChunk*> _drawChunks;
|
|
||||||
Array<JsonAssetReference<PhysicalMaterial>, FixedAllocation<8>> _physicalMaterials;
|
Array<JsonAssetReference<PhysicalMaterial>, FixedAllocation<8>> _physicalMaterials;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -424,9 +423,12 @@ private:
|
|||||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||||
void DrawPhysicsDebug(RenderView& view);
|
void DrawPhysicsDebug(RenderView& view);
|
||||||
#endif
|
#endif
|
||||||
|
bool DrawSetup(RenderContext& renderContext);
|
||||||
|
void DrawImpl(RenderContext& renderContext, HashSet<TerrainChunk*, class RendererAllocation>& drawnChunks);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// [PhysicsColliderActor]
|
// [PhysicsColliderActor]
|
||||||
|
void Draw(RenderContextBatch& renderContextBatch) override;
|
||||||
void Draw(RenderContext& renderContext) override;
|
void Draw(RenderContext& renderContext) override;
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
void OnDebugDrawSelected() override;
|
void OnDebugDrawSelected() override;
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ private:
|
|||||||
float _perInstanceRandom;
|
float _perInstanceRandom;
|
||||||
float _yOffset, _yHeight;
|
float _yOffset, _yHeight;
|
||||||
|
|
||||||
TerrainChunk* _neighbors[4];
|
TerrainChunk* _neighbors[4] = {};
|
||||||
byte _cachedDrawLOD;
|
byte _cachedDrawLOD = 0;
|
||||||
IMaterial* _cachedDrawMaterial;
|
IMaterial* _cachedDrawMaterial = nullptr;
|
||||||
|
|
||||||
void Init(TerrainPatch* patch, uint16 x, uint16 z);
|
void Init(TerrainPatch* patch, uint16 x, uint16 z);
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,11 @@ TerrainPatch::~TerrainPatch()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RawDataAsset* TerrainPatch::GetHeightfield() const
|
||||||
|
{
|
||||||
|
return _heightfield.Get();
|
||||||
|
}
|
||||||
|
|
||||||
void TerrainPatch::RemoveLightmap()
|
void TerrainPatch::RemoveLightmap()
|
||||||
{
|
{
|
||||||
for (auto& chunk : Chunks)
|
for (auto& chunk : Chunks)
|
||||||
@@ -1215,7 +1220,8 @@ Color32* TerrainPatch::GetSplatMapData(int32 index)
|
|||||||
void TerrainPatch::ClearSplatMapCache()
|
void TerrainPatch::ClearSplatMapCache()
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Terrain.ClearSplatMapCache");
|
PROFILE_CPU_NAMED("Terrain.ClearSplatMapCache");
|
||||||
_cachedSplatMap->Clear();
|
if (_cachedSplatMap)
|
||||||
|
_cachedSplatMap->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainPatch::ClearCache()
|
void TerrainPatch::ClearCache()
|
||||||
|
|||||||
@@ -149,6 +149,12 @@ public:
|
|||||||
return GetChunk(z * Terrain::ChunksCountEdge + x);
|
return GetChunk(z * Terrain::ChunksCountEdge + x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the heightfield collision data asset.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The heightfield data asset.</returns>
|
||||||
|
API_PROPERTY() RawDataAsset* GetHeightfield() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the splatmap assigned to this patch.
|
/// Gets the splatmap assigned to this patch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user