From d9dc23afc1bbaec632e172fb9dd713776481c88e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 3 Jul 2022 16:08:22 +0200 Subject: [PATCH] Fixes for Foliage with Large Worlds usage --- .../Editor/Tools/Foliage/EditFoliageGizmo.cs | 7 +- Source/Editor/Tools/Foliage/FoliageTools.cpp | 13 ++- .../Editor/Tools/Foliage/PaintFoliageGizmo.cs | 2 +- Source/Engine/Foliage/Foliage.cpp | 82 ++++++++++--------- Source/Engine/Foliage/FoliageCluster.cpp | 3 +- Source/Engine/Foliage/FoliageInstance.h | 5 -- .../Renderer/Editor/LightmapUVsDensity.cpp | 1 + .../Engine/ShadowsOfMordor/Builder.Jobs.cpp | 4 +- 8 files changed, 61 insertions(+), 56 deletions(-) diff --git a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs index 0d4c44cb5..687854b89 100644 --- a/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs +++ b/Source/Editor/Tools/Foliage/EditFoliageGizmo.cs @@ -216,10 +216,9 @@ namespace FlaxEditor.Tools.Foliage var model = foliage.GetFoliageType(instance.Type).Model; if (model) { - foliage.GetLocalToWorldMatrix(out var world); - instance.Transform.GetWorld(out var matrix); - Matrix.Multiply(ref matrix, ref world, out var instanceWorld); - model.Draw(ref renderContext, _highlightMaterial, ref instanceWorld, StaticFlags.None, false); + var transform = foliage.Transform.LocalToWorld(instance.Transform); + renderContext.View.GetWorldMatrix(ref transform, out var world); + model.Draw(ref renderContext, _highlightMaterial, ref world, StaticFlags.None, false); } } diff --git a/Source/Editor/Tools/Foliage/FoliageTools.cpp b/Source/Editor/Tools/Foliage/FoliageTools.cpp index 30133d766..cc740fdf4 100644 --- a/Source/Editor/Tools/Foliage/FoliageTools.cpp +++ b/Source/Editor/Tools/Foliage/FoliageTools.cpp @@ -250,11 +250,13 @@ void FoliageTools::Paint(Foliage* foliage, Span foliageTypesIndices, cons { // Skip if any places instance is close that placement location bool isInvalid = false; + const Transform foliageTransform = foliage->GetTransform(); // TODO: use quad tree to boost this logic for (auto i = foliage->Instances.Begin(); i.IsNotEnd(); ++i) { const auto& instance = *i; - if (Vector3::DistanceSquared(instance.World.GetTranslation(), placement.Location) <= paintRadiusSqr) + const Vector3 instancePosition = foliageTransform.LocalToWorld(instance.Transform.Translation); + if (Vector3::DistanceSquared(instancePosition, placement.Location) <= paintRadiusSqr) { isInvalid = true; break; @@ -339,11 +341,6 @@ void FoliageTools::Paint(Foliage* foliage, Span foliageTypesIndices, cons // Convert instance transformation into the local-space of the foliage actor foliage->GetTransform().WorldToLocal(instance.Transform, instance.Transform); - // Calculate foliage instance geometry transformation matrix - instance.Transform.GetWorld(matrix); - Matrix::Multiply(matrix, world, instance.World); - instance.DrawState.PrevWorld = instance.World; - // Add foliage instance foliage->AddInstance(instance); } @@ -361,12 +358,14 @@ void FoliageTools::Remove(Foliage* foliage, Span foliageTypesIndices, con // For each selected foliage instance type try to remove something const BoundingSphere brush(brushPosition, brushRadius); + const Transform foliageTransform = foliage->GetTransform(); for (auto i = foliage->Instances.Begin(); i.IsNotEnd(); ++i) { auto& instance = *i; // Skip instances outside the brush - if (CollisionsHelper::SphereContainsPoint(brush, instance.World.GetTranslation()) == ContainmentType::Disjoint) + const Vector3 instancePosition = foliageTransform.LocalToWorld(instance.Transform.Translation); + if (CollisionsHelper::SphereContainsPoint(brush, instancePosition) == ContainmentType::Disjoint) continue; // Skip instances not existing in a filter diff --git a/Source/Editor/Tools/Foliage/PaintFoliageGizmo.cs b/Source/Editor/Tools/Foliage/PaintFoliageGizmo.cs index db403ad12..456f1f73e 100644 --- a/Source/Editor/Tools/Foliage/PaintFoliageGizmo.cs +++ b/Source/Editor/Tools/Foliage/PaintFoliageGizmo.cs @@ -93,7 +93,7 @@ namespace FlaxEditor.Tools.Foliage rotation = Quaternion.RotationZ(Mathf.Pi); else rotation = Quaternion.LookRotation(Vector3.Cross(Vector3.Cross(brushNormal, Vector3.Forward), brushNormal), brushNormal); - Matrix transform = Matrix.Scaling(Mode.CurrentBrush.Size * 0.01f) * Matrix.RotationQuaternion(rotation) * Matrix.Translation(brushPosition); + Matrix transform = Matrix.Scaling(Mode.CurrentBrush.Size * 0.01f) * Matrix.RotationQuaternion(rotation) * Matrix.Translation(brushPosition - renderContext.View.Origin); _brushModel.Draw(ref renderContext, brushMaterial, ref transform); } } diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 162742811..5c9e2ce67 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -104,12 +104,15 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan // Add instance to the draw batch auto& instanceData = e->Instances.AddOne(); - instanceData.InstanceOrigin = Float3(instance.World.M41, instance.World.M42, instance.World.M43); + Matrix world; + const Transform transform = _transform.LocalToWorld(instance.Transform); + renderContext.View.GetWorldMatrix(transform, world); + instanceData.InstanceOrigin = Float3(world.M41, world.M42, world.M43); instanceData.PerInstanceRandom = instance.Random; - instanceData.InstanceTransform1 = Float3(instance.World.M11, instance.World.M12, instance.World.M13); + instanceData.InstanceTransform1 = Float3(world.M11, world.M12, world.M13); instanceData.LODDitherFactor = lodDitherFactor; - instanceData.InstanceTransform2 = Float3(instance.World.M21, instance.World.M22, instance.World.M23); - instanceData.InstanceTransform3 = Float3(instance.World.M31, instance.World.M32, instance.World.M33); + instanceData.InstanceTransform2 = Float3(world.M21, world.M22, world.M23); + instanceData.InstanceTransform3 = Float3(world.M31, world.M32, world.M33); instanceData.InstanceLightmapArea = Half4(instance.Lightmap.UVsArea); } } @@ -117,7 +120,8 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, FoliageType& type, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const { // Skip clusters that around too far from view - if (Vector3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center) - cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance) + const Vector3 viewOrigin = renderContext.View.Origin; + if (Float3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center - viewOrigin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance) return; //DebugDraw::DrawBox(cluster->Bounds, Color::Red); @@ -128,8 +132,12 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, // Don't store instances in non-leaf nodes ASSERT_LOW_LAYER(cluster->Instances.IsEmpty()); + BoundingBox box; #define DRAW_CLUSTER(idx) \ - if (renderContext.View.CullingFrustum.Intersects(cluster->Children[idx]->TotalBounds)) \ + box = cluster->Children[idx]->TotalBounds; \ + box.Minimum -= viewOrigin; \ + box.Maximum -= viewOrigin; \ + if (renderContext.View.CullingFrustum.Intersects(box)) \ DrawCluster(renderContext, cluster->Children[idx], type, drawCallsLists, result) DRAW_CLUSTER(0); DRAW_CLUSTER(1); @@ -145,13 +153,15 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, for (int32 i = 0; i < cluster->Instances.Count(); i++) { auto& instance = *cluster->Instances[i]; - if (Vector3::Distance(renderContext.View.Position, instance.Bounds.Center) - instance.Bounds.Radius < instance.CullDistance && - renderContext.View.CullingFrustum.Intersects(instance.Bounds)) + BoundingSphere sphere = instance.Bounds; + sphere.Center -= viewOrigin; + if (Float3::Distance(renderContext.View.Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance && + renderContext.View.CullingFrustum.Intersects(sphere)) { const auto modelFrame = instance.DrawState.PrevFrame + 1; // Select a proper LOD index (model may be culled) - int32 lodIndex = RenderTools::ComputeModelLOD(model, instance.Bounds.Center, (float)instance.Bounds.Radius, renderContext); // TODO: large-worlds + int32 lodIndex = RenderTools::ComputeModelLOD(model, sphere.Center, (float)sphere.Radius, renderContext); if (lodIndex == -1) { // Handling model fade-out transition @@ -239,7 +249,8 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, Mesh::DrawInfo& draw) { // Skip clusters that around too far from view - if (Vector3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center) - cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance) + const Vector3 viewOrigin = renderContext.View.Origin; + if (Float3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center - viewOrigin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance) return; //DebugDraw::DrawBox(cluster->Bounds, Color::Red); @@ -250,8 +261,12 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, // Don't store instances in non-leaf nodes ASSERT_LOW_LAYER(cluster->Instances.IsEmpty()); + BoundingBox box; #define DRAW_CLUSTER(idx) \ - if (renderContext.View.CullingFrustum.Intersects(cluster->Children[idx]->TotalBounds)) \ + box = cluster->Children[idx]->TotalBounds; \ + box.Minimum -= viewOrigin; \ + box.Maximum -= viewOrigin; \ + if (renderContext.View.CullingFrustum.Intersects(box)) \ DrawCluster(renderContext, cluster->Children[idx], draw) DRAW_CLUSTER(0); DRAW_CLUSTER(1); @@ -267,22 +282,28 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, { auto& instance = *cluster->Instances[i]; auto& type = FoliageTypes[instance.Type]; + BoundingSphere sphere = instance.Bounds; + sphere.Center -= viewOrigin; // Check if can draw this instance if (type._canDraw && - Vector3::Distance(renderContext.View.Position, instance.Bounds.Center) - instance.Bounds.Radius < instance.CullDistance && - renderContext.View.CullingFrustum.Intersects(instance.Bounds)) + Float3::Distance(renderContext.View.Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance && + renderContext.View.CullingFrustum.Intersects(sphere)) { + Matrix world; + const Transform transform = _transform.LocalToWorld(instance.Transform); + renderContext.View.GetWorldMatrix(transform, world); + // Disable motion blur - instance.DrawState.PrevWorld = instance.World; + instance.DrawState.PrevWorld = world; // Draw model draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(instance.Lightmap.TextureIndex); draw.LightmapUVs = &instance.Lightmap.UVsArea; draw.Buffer = &type.Entries; - draw.World = &instance.World; + draw.World = &world; draw.DrawState = &instance.DrawState; - draw.Bounds = instance.Bounds; + draw.Bounds = sphere; draw.PerInstanceRandom = instance.Random; draw.DrawModes = type._drawModes; type.Model->Draw(renderContext, draw); @@ -411,13 +432,6 @@ void Foliage::AddInstance(const FoliageInstance& instance) data->Random = Random::Rand(); data->CullDistance = type->CullDistance + type->CullDistanceRandomRange * data->Random; - // Calculate foliage instance geometry transformation matrix - Matrix matrix, world; - GetLocalToWorldMatrix(world); - data->Transform.GetWorld(matrix); - Matrix::Multiply(matrix, world, data->World); - data->DrawState.PrevWorld = data->World; - // Validate foliage type model if (!type->IsReady()) return; @@ -425,13 +439,14 @@ void Foliage::AddInstance(const FoliageInstance& instance) // Update bounds Vector3 corners[8]; auto& meshes = type->Model->LODs[0].Meshes; + const Transform transform = _transform.LocalToWorld(data->Transform); for (int32 j = 0; j < meshes.Count(); j++) { meshes[j].GetBox().GetCorners(corners); for (int32 k = 0; k < 8; k++) { - Vector3::Transform(corners[k], data->World, corners[k]); + Vector3::Transform(corners[k], transform, corners[k]); } BoundingSphere meshBounds; BoundingSphere::FromPoints(corners, 8, meshBounds); @@ -455,25 +470,20 @@ void Foliage::SetInstanceTransform(int32 index, const Transform& value) // Change transform instance.Transform = value; - // Update world matrix - Matrix matrix, world; - GetLocalToWorldMatrix(world); - instance.Transform.GetWorld(matrix); - Matrix::Multiply(matrix, world, instance.World); - // Update bounds instance.Bounds = BoundingSphere::Empty; if (!type->IsReady()) return; Vector3 corners[8]; auto& meshes = type->Model->LODs[0].Meshes; + const Transform transform = _transform.LocalToWorld(instance.Transform); for (int32 j = 0; j < meshes.Count(); j++) { meshes[j].GetBox().GetCorners(corners); for (int32 k = 0; k < 8; k++) { - Vector3::Transform(corners[k], instance.World, corners[k]); + Vector3::Transform(corners[k], transform, corners[k]); } BoundingSphere meshBounds; BoundingSphere::FromPoints(corners, 8, meshBounds); @@ -507,6 +517,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index) if (instance.Type != index) continue; instance.Bounds = BoundingSphere::Empty; + const Transform transform = _transform.LocalToWorld(instance.Transform); // Include all meshes for (int32 j = 0; j < meshes.Count(); j++) @@ -517,7 +528,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index) // TODO: use SIMD for (int32 k = 0; k < 8; k++) { - Vector3::Transform(corners[k], instance.World, corners[k]); + Vector3::Transform(corners[k], transform, corners[k]); } BoundingSphere meshBounds; BoundingSphere::FromPoints(corners, 8, meshBounds); @@ -1271,22 +1282,19 @@ void Foliage::OnTransformChanged() auto& instance = *i; auto type = &FoliageTypes[instance.Type]; - // Update world matrix - instance.Transform.GetWorld(matrix); - Matrix::Multiply(matrix, world, instance.World); - // Update bounds instance.Bounds = BoundingSphere::Empty; if (!type->IsReady()) continue; auto& meshes = type->Model->LODs[0].Meshes; + const Transform transform = _transform.LocalToWorld(instance.Transform); for (int32 j = 0; j < meshes.Count(); j++) { meshes[j].GetBox().GetCorners(corners); for (int32 k = 0; k < 8; k++) { - Vector3::Transform(corners[k], instance.World, corners[k]); + Vector3::Transform(corners[k], transform, corners[k]); } BoundingSphere meshBounds; BoundingSphere::FromPoints(corners, 8, meshBounds); diff --git a/Source/Engine/Foliage/FoliageCluster.cpp b/Source/Engine/Foliage/FoliageCluster.cpp index c7fceb6e5..ac6bce397 100644 --- a/Source/Engine/Foliage/FoliageCluster.cpp +++ b/Source/Engine/Foliage/FoliageCluster.cpp @@ -118,7 +118,8 @@ bool FoliageCluster::Intersects(Foliage* foliage, const Ray& ray, Real& distance { auto& ii = *Instances[i]; auto& type = foliage->FoliageTypes[ii.Type]; - if (type.IsReady() && ii.Bounds.Intersects(ray) && type.Model->Intersects(ray, ii.World, distance, normal, &mesh) && minDistance > distance) + const Transform transform = foliage->GetTransform().LocalToWorld(ii.Transform); + if (type.IsReady() && ii.Bounds.Intersects(ray) && type.Model->Intersects(ray, transform, distance, normal, &mesh) && minDistance > distance) { minDistanceNormal = normal; minDistance = distance; diff --git a/Source/Engine/Foliage/FoliageInstance.h b/Source/Engine/Foliage/FoliageInstance.h index de823358c..4f64619af 100644 --- a/Source/Engine/Foliage/FoliageInstance.h +++ b/Source/Engine/Foliage/FoliageInstance.h @@ -19,11 +19,6 @@ API_STRUCT(NoPod) struct FLAXENGINE_API FoliageInstance /// API_FIELD() Transform Transform; - /// - /// The cached world transformation matrix of this instance. - /// - API_FIELD() Matrix World; - /// /// The model drawing state. /// diff --git a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp index 057ccd1d2..44b947906 100644 --- a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp +++ b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp @@ -72,6 +72,7 @@ namespace { Actor* FindActorByDrawCall(Actor* actor, const DrawCall& drawCall, float& scaleInLightmap) { + // TODO: large-worlds const auto asStaticModel = ScriptingObject::Cast(actor); if (asStaticModel && asStaticModel->GetPerInstanceRandom() == drawCall.PerInstanceRandom && asStaticModel->GetPosition() == drawCall.ObjectPosition) { diff --git a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp index b8412ac64..cffbb6043 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp @@ -188,7 +188,9 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context) auto& instance = foliage->Instances[entry.AsFoliage.InstanceIndex]; auto& type = foliage->FoliageTypes[entry.AsFoliage.TypeIndex]; - Matrix::Transpose(instance.World, shaderData.WorldMatrix); + Matrix world; + foliage->GetTransform().LocalToWorld(instance.Transform).GetWorld(world); + Matrix::Transpose(world, shaderData.WorldMatrix); shaderData.LightmapArea = instance.Lightmap.UVsArea; context->UpdateCB(cb, &shaderData);