diff --git a/Source/Editor/Tools/Foliage/FoliageTools.cpp b/Source/Editor/Tools/Foliage/FoliageTools.cpp
index 30bdb5dfd..30133d766 100644
--- a/Source/Editor/Tools/Foliage/FoliageTools.cpp
+++ b/Source/Editor/Tools/Foliage/FoliageTools.cpp
@@ -80,9 +80,10 @@ struct GeometryLookup
PROFILE_CPU_NAMED("StaticModel");
// Check model meshes
- Matrix world;
- staticModel->GetWorld(&world);
- const bool isDeterminantPositive = staticModel->GetTransform().GetDeterminant() >= 0.0f;
+ Transform transform = staticModel->GetTransform();
+ Matrix worldMatrix;
+ transform.GetWorld(worldMatrix);
+ const bool isDeterminantPositive = transform.GetDeterminant() >= 0.0f;
auto& lod = staticModel->Model->LODs[0];
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
{
@@ -96,9 +97,9 @@ struct GeometryLookup
// Transform triangle vertices from mesh space to world space
Vector3 t0, t1, t2;
- Vector3::Transform(t.V0, world, t0);
- Vector3::Transform(t.V1, world, t1);
- Vector3::Transform(t.V2, world, t2);
+ Vector3::Transform(t.V0, worldMatrix, t0);
+ Vector3::Transform(t.V1, worldMatrix, t1);
+ Vector3::Transform(t.V2, worldMatrix, t2);
// Check if triangles intersects with the brush
if (CollisionsHelper::SphereIntersectsTriangle(brush, t0, t1, t2))
diff --git a/Source/Editor/Utilities/ViewportIconsRenderer.cpp b/Source/Editor/Utilities/ViewportIconsRenderer.cpp
index 450bc5052..8b8e0d74f 100644
--- a/Source/Editor/Utilities/ViewportIconsRenderer.cpp
+++ b/Source/Editor/Utilities/ViewportIconsRenderer.cpp
@@ -93,7 +93,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
Matrix m1, m2, world;
for (Actor* icon : icons)
{
- BoundingSphere sphere(icon->GetPosition(), ICON_RADIUS);
+ BoundingSphere sphere(icon->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
IconTypes iconType;
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(icon->GetTypeHandle(), iconType))
{
@@ -120,7 +120,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
auto& view = renderContext.View;
const BoundingFrustum frustum = view.Frustum;
Matrix m1, m2, world;
- BoundingSphere sphere(actor->GetPosition(), ICON_RADIUS);
+ BoundingSphere sphere(actor->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
IconTypes iconType;
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType))
{
diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index ae89ed7df..110ab657c 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -777,16 +777,16 @@ namespace FlaxEditor.Viewport
/// The view.
public void CopyViewData(ref RenderView view)
{
- // Create matrices
- CreateProjectionMatrix(out view.Projection);
- CreateViewMatrix(out view.View);
-
- // Copy data
- view.Position = ViewPosition;
+ Vector3 position = ViewPosition;
+ LargeWorlds.UpdateOrigin(ref view.Origin, position);
+ view.Position = position - view.Origin;
view.Direction = ViewDirection;
view.Near = _nearPlane;
view.Far = _farPlane;
+ CreateProjectionMatrix(out view.Projection);
+ CreateViewMatrix(view.Position, out view.View);
+
view.UpdateCachedData();
}
@@ -828,10 +828,10 @@ namespace FlaxEditor.Viewport
///
/// Creates the view matrix.
///
+ /// The view position.
/// The result.
- protected virtual void CreateViewMatrix(out Matrix result)
+ protected virtual void CreateViewMatrix(Float3 position, out Matrix result)
{
- var position = (Float3)ViewPosition; // TODO: large-worlds
var direction = ViewDirection;
var target = position + direction;
var right = Float3.Normalize(Float3.Cross(Float3.Up, direction));
@@ -862,7 +862,7 @@ namespace FlaxEditor.Viewport
// Prepare
var viewport = new FlaxEngine.Viewport(0, 0, Width, Height);
CreateProjectionMatrix(out var p);
- CreateViewMatrix(out var v);
+ CreateViewMatrix(Float3.Zero, out var v); // TODO: large-worlds
Matrix.Multiply(ref v, ref p, out var ivp);
ivp.Invert();
diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp
index 4dcdcf3e2..11ccd841a 100644
--- a/Source/Engine/Content/Assets/Model.cpp
+++ b/Source/Engine/Content/Assets/Model.cpp
@@ -172,6 +172,11 @@ bool Model::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vect
return LODs[lodIndex].Intersects(ray, world, distance, normal, mesh);
}
+bool Model::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh, int32 lodIndex)
+{
+ return LODs[lodIndex].Intersects(ray, transform, distance, normal, mesh);
+}
+
BoundingBox Model::GetBox(const Matrix& world, int32 lodIndex) const
{
return LODs[lodIndex].GetBox(world);
diff --git a/Source/Engine/Content/Assets/Model.h b/Source/Engine/Content/Assets/Model.h
index 9156582d2..dba0df965 100644
--- a/Source/Engine/Content/Assets/Model.h
+++ b/Source/Engine/Content/Assets/Model.h
@@ -134,6 +134,18 @@ public:
/// True whether the two objects intersected
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh, int32 lodIndex = 0);
+ ///
+ /// Determines if there is an intersection between the Model and a Ray in given world using given instance.
+ ///
+ /// The ray to test
+ /// The instance transformation.
+ /// When the method completes, contains the distance of the intersection (if any valid).
+ /// When the method completes, contains the intersection surface normal vector (if any valid).
+ /// Mesh, or null
+ /// Level Of Detail index
+ /// True whether the two objects intersected
+ bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh, int32 lodIndex = 0);
+
///
/// Gets the model bounding box in custom matrix world space.
///
@@ -142,6 +154,17 @@ public:
/// The bounding box.
API_FUNCTION() BoundingBox GetBox(const Matrix& world, int32 lodIndex = 0) const;
+ ///
+ /// Gets the model bounding box in custom transformation.
+ ///
+ /// The instance transformation.
+ /// The Level Of Detail index.
+ /// The bounding box.
+ API_FUNCTION() BoundingBox GetBox(const Transform& transform, int32 lodIndex = 0) const
+ {
+ return LODs[lodIndex].GetBox(transform);
+ }
+
///
/// Gets the model bounding box in local space.
///
diff --git a/Source/Engine/Core/Math/BoundingFrustum.cpp b/Source/Engine/Core/Math/BoundingFrustum.cpp
index 88e3467c8..88f35b8ca 100644
--- a/Source/Engine/Core/Math/BoundingFrustum.cpp
+++ b/Source/Engine/Core/Math/BoundingFrustum.cpp
@@ -134,8 +134,7 @@ float BoundingFrustum::GetHeightAtDepth(float depth) const
ContainmentType BoundingFrustum::Contains(const Vector3& point) const
{
PlaneIntersectionType result = PlaneIntersectionType::Front;
- PlaneIntersectionType planeResult = PlaneIntersectionType::Front;
- for (int i = 0; i < 6; i++)
+ for (int32 i = 0; i < 6; i++)
{
const PlaneIntersectionType planeResult = _planes[i].Intersects(point);
switch (planeResult)
@@ -159,7 +158,7 @@ ContainmentType BoundingFrustum::Contains(const Vector3& point) const
ContainmentType BoundingFrustum::Contains(const BoundingSphere& sphere) const
{
auto result = PlaneIntersectionType::Front;
- for (int i = 0; i < 6; i++)
+ for (int32 i = 0; i < 6; i++)
{
const PlaneIntersectionType planeResult = _planes[i].Intersects(sphere);
switch (planeResult)
diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp
index 76056ac44..162742811 100644
--- a/Source/Engine/Foliage/Foliage.cpp
+++ b/Source/Engine/Foliage/Foliage.cpp
@@ -427,7 +427,7 @@ void Foliage::AddInstance(const FoliageInstance& instance)
auto& meshes = type->Model->LODs[0].Meshes;
for (int32 j = 0; j < meshes.Count(); j++)
{
- meshes[j].GetCorners(corners);
+ meshes[j].GetBox().GetCorners(corners);
for (int32 k = 0; k < 8; k++)
{
@@ -469,7 +469,7 @@ void Foliage::SetInstanceTransform(int32 index, const Transform& value)
auto& meshes = type->Model->LODs[0].Meshes;
for (int32 j = 0; j < meshes.Count(); j++)
{
- meshes[j].GetCorners(corners);
+ meshes[j].GetBox().GetCorners(corners);
for (int32 k = 0; k < 8; k++)
{
@@ -512,7 +512,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index)
for (int32 j = 0; j < meshes.Count(); j++)
{
// TODO: cache bounds for all model meshes and reuse later
- meshes[j].GetCorners(corners);
+ meshes[j].GetBox().GetCorners(corners);
// TODO: use SIMD
for (int32 k = 0; k < 8; k++)
@@ -1282,7 +1282,7 @@ void Foliage::OnTransformChanged()
auto& meshes = type->Model->LODs[0].Meshes;
for (int32 j = 0; j < meshes.Count(); j++)
{
- meshes[j].GetCorners(corners);
+ meshes[j].GetBox().GetCorners(corners);
for (int32 k = 0; k < 8; k++)
{
diff --git a/Source/Engine/Graphics/Models/CollisionProxy.h b/Source/Engine/Graphics/Models/CollisionProxy.h
index 346eb8e25..d19f43949 100644
--- a/Source/Engine/Graphics/Models/CollisionProxy.h
+++ b/Source/Engine/Graphics/Models/CollisionProxy.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Core/Math/Vector3.h"
+#include "Engine/Core/Math/Transform.h"
#include "Engine/Core/Math/Ray.h"
#include "Engine/Core/Math/CollisionsHelper.h"
#include "Engine/Core/Collections/Array.h"
@@ -74,4 +75,26 @@ public:
}
return false;
}
+
+ bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const
+ {
+ for (int32 i = 0; i < Triangles.Count(); i++)
+ {
+ CollisionTriangle triangle = Triangles[i];
+ Vector3 v0, v1, v2;
+ transform.LocalToWorld(triangle.V0, v0);
+ transform.LocalToWorld(triangle.V1, v1);
+ transform.LocalToWorld(triangle.V2, v2);
+
+ // TODO: use 32-bit precision for intersection
+ Real d;
+ if (CollisionsHelper::RayIntersectsTriangle(ray, triangle.V0, triangle.V1, triangle.V2, d))
+ {
+ normal = Vector3::Normalize((triangle.V1 - triangle.V0) ^ (triangle.V2 - triangle.V0));
+ distance = d;
+ return true;
+ }
+ }
+ return false;
+ }
};
diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp
index c39125d04..dc847a471 100644
--- a/Source/Engine/Graphics/Models/Mesh.cpp
+++ b/Source/Engine/Graphics/Models/Mesh.cpp
@@ -4,6 +4,7 @@
#include "ModelInstanceEntry.h"
#include "Engine/Content/Assets/Material.h"
#include "Engine/Content/Assets/Model.h"
+#include "Engine/Core/Math/Transform.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/RenderTask.h"
@@ -319,7 +320,7 @@ bool Mesh::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vecto
{
// Get bounding box of the mesh bounds transformed by the instance world matrix
Vector3 corners[8];
- GetCorners(corners);
+ _box.GetCorners(corners);
Vector3 tmp;
Vector3::Transform(corners[0], world, tmp);
Vector3 min = tmp;
@@ -339,7 +340,38 @@ bool Mesh::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vecto
// Use exact test on raw geometry
return _collisionProxy.Intersects(ray, world, distance, normal);
}
+ distance = 0;
+ normal = Vector3::Up;
+ return false;
+#else
+ return transformedBox.Intersects(ray, distance, normal);
+#endif
+}
+bool Mesh::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const
+{
+ // Get bounding box of the mesh bounds transformed by the instance world matrix
+ Vector3 corners[8];
+ _box.GetCorners(corners);
+ Vector3 tmp;
+ transform.LocalToWorld(corners[0], tmp);
+ Vector3 min = tmp;
+ Vector3 max = tmp;
+ for (int32 i = 1; i < 8; i++)
+ {
+ transform.LocalToWorld(corners[i], tmp);
+ min = Vector3::Min(min, tmp);
+ max = Vector3::Max(max, tmp);
+ }
+ const BoundingBox transformedBox(min, max);
+
+ // Test ray on box
+#if USE_PRECISE_MESH_INTERSECTS
+ if (transformedBox.Intersects(ray, distance))
+ {
+ // Use exact test on raw geometry
+ return _collisionProxy.Intersects(ray, transform, distance, normal);
+ }
distance = 0;
normal = Vector3::Up;
return false;
diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h
index 9d1dd01e0..5be9ea018 100644
--- a/Source/Engine/Graphics/Models/Mesh.h
+++ b/Source/Engine/Graphics/Models/Mesh.h
@@ -259,13 +259,14 @@ public:
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const;
///
- /// Retrieves the eight corners of the bounding box.
+ /// Determines if there is an intersection between the mesh and a ray in given world
///
- /// An array of points representing the eight corners of the bounding box.
- FORCE_INLINE void GetCorners(Vector3 corners[8]) const
- {
- _box.GetCorners(corners);
- }
+ /// The ray to test
+ /// The instance transformation.
+ /// When the method completes and returns true, contains the distance of the intersection (if any valid).
+ /// When the method completes, contains the intersection surface normal vector (if any valid).
+ /// True whether the two objects intersected
+ bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const;
public:
///
diff --git a/Source/Engine/Graphics/Models/ModelLOD.cpp b/Source/Engine/Graphics/Models/ModelLOD.cpp
index a6b6e9980..ec71f7b7e 100644
--- a/Source/Engine/Graphics/Models/ModelLOD.cpp
+++ b/Source/Engine/Graphics/Models/ModelLOD.cpp
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "ModelLOD.h"
+#include "Engine/Core/Math/Transform.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Serialization/MemoryReadStream.h"
@@ -60,13 +61,11 @@ void ModelLOD::Dispose()
bool ModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh)
{
- // Check all meshes
bool result = false;
Real closest = MAX_Real;
Vector3 closestNormal = Vector3::Up;
for (int32 i = 0; i < Meshes.Count(); i++)
{
- // Test intersection with mesh and check if is closer than previous
Real dst;
Vector3 nrm;
if (Meshes[i].Intersects(ray, world, dst, nrm) && dst < closest)
@@ -77,7 +76,28 @@ bool ModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, V
closestNormal = nrm;
}
}
+ distance = closest;
+ normal = closestNormal;
+ return result;
+}
+bool ModelLOD::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh)
+{
+ bool result = false;
+ Real closest = MAX_Real;
+ Vector3 closestNormal = Vector3::Up;
+ for (int32 i = 0; i < Meshes.Count(); i++)
+ {
+ Real dst;
+ Vector3 nrm;
+ if (Meshes[i].Intersects(ray, transform, dst, nrm) && dst < closest)
+ {
+ result = true;
+ *mesh = &Meshes[i];
+ closest = dst;
+ closestNormal = nrm;
+ }
+ }
distance = closest;
normal = closestNormal;
return result;
@@ -85,14 +105,12 @@ bool ModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, V
BoundingBox ModelLOD::GetBox(const Matrix& world) const
{
- // Find minimum and maximum points of all the meshes
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
Vector3 corners[8];
for (int32 j = 0; j < Meshes.Count(); j++)
{
const auto& mesh = Meshes[j];
- mesh.GetCorners(corners);
-
+ mesh.GetBox().GetCorners(corners);
for (int32 i = 0; i < 8; i++)
{
Vector3::Transform(corners[i], world, tmp);
@@ -100,42 +118,39 @@ BoundingBox ModelLOD::GetBox(const Matrix& world) const
max = Vector3::Max(max, tmp);
}
}
-
return BoundingBox(min, max);
}
-BoundingBox ModelLOD::GetBox(const Matrix& world, int32 meshIndex) const
+BoundingBox ModelLOD::GetBox(const Transform& transform) const
{
- // Find minimum and maximum points of the mesh
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
Vector3 corners[8];
- const auto& mesh = Meshes[meshIndex];
- mesh.GetCorners(corners);
- for (int32 i = 0; i < 8; i++)
+ for (int32 j = 0; j < Meshes.Count(); j++)
{
- Vector3::Transform(corners[i], world, tmp);
- min = Vector3::Min(min, tmp);
- max = Vector3::Max(max, tmp);
+ const auto& mesh = Meshes[j];
+ mesh.GetBox().GetCorners(corners);
+ for (int32 i = 0; i < 8; i++)
+ {
+ transform.LocalToWorld(corners[i], tmp);
+ min = Vector3::Min(min, tmp);
+ max = Vector3::Max(max, tmp);
+ }
}
-
return BoundingBox(min, max);
}
BoundingBox ModelLOD::GetBox() const
{
- // Find minimum and maximum points of the mesh in given world
Vector3 min = Vector3::Maximum, max = Vector3::Minimum;
Vector3 corners[8];
for (int32 j = 0; j < Meshes.Count(); j++)
{
- Meshes[j].GetCorners(corners);
-
+ Meshes[j].GetBox().GetCorners(corners);
for (int32 i = 0; i < 8; i++)
{
min = Vector3::Min(min, corners[i]);
max = Vector3::Max(max, corners[i]);
}
}
-
return BoundingBox(min, max);
}
diff --git a/Source/Engine/Graphics/Models/ModelLOD.h b/Source/Engine/Graphics/Models/ModelLOD.h
index 745f3ac16..fb3363ecc 100644
--- a/Source/Engine/Graphics/Models/ModelLOD.h
+++ b/Source/Engine/Graphics/Models/ModelLOD.h
@@ -79,19 +79,29 @@ public:
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh);
///
- /// Get model bounding box in transformed world for given instance buffer
+ /// Determines if there is an intersection between the Model and a Ray in given world using given instance
+ ///
+ /// The ray to test
+ /// The instance transformation.
+ /// When the method completes, contains the distance of the intersection (if any valid).
+ /// When the method completes, contains the intersection surface normal vector (if any valid).
+ /// Mesh, or null
+ /// True whether the two objects intersected
+ bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh);
+
+ ///
+ /// Get model bounding box in transformed world matrix.
///
/// World matrix
/// Bounding box
BoundingBox GetBox(const Matrix& world) const;
///
- /// Get model bounding box in transformed world for given instance buffer for only one mesh
+ /// Get model bounding box in transformed world.
///
- /// World matrix
- /// esh index
+ /// The instance transformation.
/// Bounding box
- BoundingBox GetBox(const Matrix& world, int32 meshIndex) const;
+ BoundingBox GetBox(const Transform& transform) const;
///
/// Gets the bounding box combined for all meshes in this model LOD.
diff --git a/Source/Engine/Graphics/RenderTask.cpp b/Source/Engine/Graphics/RenderTask.cpp
index c93743480..6e6a9a919 100644
--- a/Source/Engine/Graphics/RenderTask.cpp
+++ b/Source/Engine/Graphics/RenderTask.cpp
@@ -255,6 +255,9 @@ void SceneRenderTask::ClearCustomActors()
void SceneRenderTask::CollectPostFxVolumes(RenderContext& renderContext)
{
+ // Cache WorldPosition used for PostFx volumes blending (RenderView caches it later on)
+ renderContext.View.WorldPosition = renderContext.View.Origin + renderContext.View.Position;
+
if ((ActorsSource & ActorsSources::Scenes) != 0)
{
Level::CollectPostFxVolumes(renderContext);
diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp
index d5f77e8b1..574add86d 100644
--- a/Source/Engine/Graphics/RenderView.cpp
+++ b/Source/Engine/Graphics/RenderView.cpp
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "RenderView.h"
+#include "Engine/Level/LargeWorlds.h"
#include "Engine/Level/Actors/Camera.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Renderer/RendererPass.h"
@@ -70,6 +71,8 @@ void RenderView::PrepareCache(RenderContext& renderContext, float width, float h
TemporalAAJitter.X = temporalAAJitter.X;
TemporalAAJitter.Y = temporalAAJitter.Y;
+ WorldPosition = Origin + Position;
+
// Ortho views have issues with screen size LOD culling
const float modelLODDistanceFactor = (renderContext.LodProxyView ? renderContext.LodProxyView->IsOrthographicProjection() : IsOrthographicProjection()) ? 100.0f : ModelLODDistanceFactor;
ModelLODDistanceFactorSqrt = modelLODDistanceFactor * modelLODDistanceFactor;
@@ -161,31 +164,15 @@ void RenderView::SetProjector(float nearPlane, float farPlane, const Float3& pos
CullingFrustum = Frustum;
}
-void RenderView::CopyFrom(Camera* camera)
-{
- Position = camera->GetPosition();
- Direction = camera->GetDirection();
- Near = camera->GetNearPlane();
- Far = camera->GetFarPlane();
- View = camera->GetView();
- Projection = camera->GetProjection();
- NonJitteredProjection = Projection;
- Frustum = camera->GetFrustum();
- Matrix::Invert(View, IV);
- Matrix::Invert(Projection, IP);
- Frustum.GetInvMatrix(IVP);
- CullingFrustum = Frustum;
- RenderLayersMask = camera->RenderLayersMask;
-}
-
void RenderView::CopyFrom(Camera* camera, Viewport* viewport)
{
- Position = camera->GetPosition();
+ const Vector3 cameraPos = camera->GetPosition();
+ LargeWorlds::UpdateOrigin(Origin, cameraPos);
+ Position = cameraPos - Origin;
Direction = camera->GetDirection();
Near = camera->GetNearPlane();
Far = camera->GetFarPlane();
- View = camera->GetView();
- camera->GetMatrices(View, Projection, *viewport);
+ camera->GetMatrices(View, Projection, viewport ? *viewport : camera->GetViewport(), Origin);
Frustum.SetMatrix(View, Projection);
NonJitteredProjection = Projection;
Matrix::Invert(View, IV);
@@ -211,3 +198,9 @@ DrawPass RenderView::GetShadowsDrawPassMask(ShadowsCastingMode shadowsMode) cons
return DrawPass::All;
}
}
+
+void RenderView::GetWorldMatrix(const Transform& transform, Matrix& world) const
+{
+ const Vector3 translation = transform.Translation - Origin;
+ Matrix::Transformation(transform.Scale, transform.Orientation, translation, world);
+}
diff --git a/Source/Engine/Graphics/RenderView.cs b/Source/Engine/Graphics/RenderView.cs
index e9b1015ae..7b54ab9ba 100644
--- a/Source/Engine/Graphics/RenderView.cs
+++ b/Source/Engine/Graphics/RenderView.cs
@@ -79,31 +79,24 @@ namespace FlaxEngine
/// The camera.
public void CopyFrom(Camera camera)
{
- Position = camera.Position;
- Direction = camera.Direction;
- Near = camera.NearPlane;
- Far = camera.FarPlane;
- View = camera.View;
- Projection = camera.Projection;
- NonJitteredProjection = Projection;
- TemporalAAJitter = Float4.Zero;
- RenderLayersMask = camera.RenderLayersMask;
-
- UpdateCachedData();
+ var viewport = camera.Viewport;
+ CopyFrom(camera, ref viewport);
}
///
/// Copies render view data from the camera.
///
/// The camera.
- /// The custom viewport to use for view/projeection matrices override.
- public void CopyFrom(Camera camera, ref Viewport customViewport)
+ /// The custom viewport to use for view/projeection matrices override.
+ public void CopyFrom(Camera camera, ref Viewport viewport)
{
- Position = camera.Position;
+ Vector3 cameraPos = camera.Position;
+ LargeWorlds.UpdateOrigin(ref Origin, cameraPos);
+ Position = cameraPos - Origin;
Direction = camera.Direction;
Near = camera.NearPlane;
Far = camera.FarPlane;
- camera.GetMatrices(out View, out Projection, ref customViewport);
+ camera.GetMatrices(out View, out Projection, ref viewport, ref Origin);
NonJitteredProjection = Projection;
TemporalAAJitter = Float4.Zero;
RenderLayersMask = camera.RenderLayersMask;
diff --git a/Source/Engine/Graphics/RenderView.h b/Source/Engine/Graphics/RenderView.h
index b06befda3..e4603d51e 100644
--- a/Source/Engine/Graphics/RenderView.h
+++ b/Source/Engine/Graphics/RenderView.h
@@ -24,7 +24,17 @@ API_STRUCT() struct FLAXENGINE_API RenderView
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderView);
///
- /// The position of the view.
+ /// The position of the view origin (in world-units). Used for camera-relative rendering to achieve large worlds support with keeping 32-bit precision for coordinates in scene rendering.
+ ///
+ API_FIELD() Vector3 Origin = Vector3::Zero;
+
+ ///
+ /// The global position of the view (Origin+Position).
+ ///
+ API_FIELD() Vector3 WorldPosition;
+
+ ///
+ /// The position of the view (relative to the origin).
///
API_FIELD() Float3 Position;
@@ -264,14 +274,10 @@ public:
/// Camera's FOV angle (in degrees)
void SetProjector(float nearPlane, float farPlane, const Float3& position, const Float3& direction, const Float3& up, float angle);
- // Copy view data from camera
- // @param camera Camera to copy its data
- void CopyFrom(Camera* camera);
-
// Copy view data from camera
// @param camera Camera to copy its data
// @param camera The custom viewport to use for view/projection matrices override.
- void CopyFrom(Camera* camera, Viewport* viewport);
+ void CopyFrom(Camera* camera, Viewport* viewport = nullptr);
public:
DrawPass GetShadowsDrawPassMask(ShadowsCastingMode shadowsMode) const;
@@ -288,4 +294,7 @@ public:
{
return Frustum.GetMatrix();
}
+
+ // Calculates the world matrix for the given transformation instance rendering.
+ void GetWorldMatrix(const Transform& transform, Matrix& world) const;
};
diff --git a/Source/Engine/Level/Actors/BoxVolume.cpp b/Source/Engine/Level/Actors/BoxVolume.cpp
index 824745fd5..b7684ad90 100644
--- a/Source/Engine/Level/Actors/BoxVolume.cpp
+++ b/Source/Engine/Level/Actors/BoxVolume.cpp
@@ -17,7 +17,7 @@ void BoxVolume::SetSize(const Vector3& value)
const auto prevBounds = _box;
_size = value;
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
- _bounds.Transform(_transform.GetWorld());
+ _bounds.Transform(_transform);
_bounds.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
OnBoundsChanged(prevBounds);
@@ -142,7 +142,7 @@ void BoxVolume::OnTransformChanged()
const auto prevBounds = _box;
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
- _bounds.Transform(_transform.GetWorld());
+ _bounds.Transform(_transform);
_bounds.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
OnBoundsChanged(prevBounds);
diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp
index 6a6c5626b..673af868e 100644
--- a/Source/Engine/Level/Actors/Camera.cpp
+++ b/Source/Engine/Level/Actors/Camera.cpp
@@ -189,10 +189,15 @@ Viewport Camera::GetViewport() const
void Camera::GetMatrices(Matrix& view, Matrix& projection) const
{
- GetMatrices(view, projection, GetViewport());
+ GetMatrices(view, projection, GetViewport(), Vector3::Zero);
}
void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewport) const
+{
+ GetMatrices(view, projection, viewport, Vector3::Zero);
+}
+
+void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewport, const Vector3& origin) const
{
// Create projection matrix
if (_usePerspective)
@@ -207,10 +212,11 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp
// Create view matrix
const Float3 direction = GetDirection();
- const Vector3 target = _transform.Translation + direction;
- Vector3 up;
- Vector3::Transform(Vector3::Up, GetOrientation(), up);
- Matrix::LookAt(_transform.Translation, target, up, view);
+ const Float3 position = _transform.Translation - origin;
+ const Float3 target = position + direction;
+ Float3 up;
+ Float3::Transform(Float3::Up, GetOrientation(), up);
+ Matrix::LookAt(position, target, up, view);
}
#if USE_EDITOR
@@ -253,16 +259,19 @@ void Camera::Draw(RenderContext& renderContext)
&& _previewModel
&& _previewModel->IsLoaded())
{
+ Matrix world;
+ renderContext.View.GetWorldMatrix(_transform, world);
GeometryDrawStateData drawState;
Mesh::DrawInfo draw;
draw.Buffer = &_previewModelBuffer;
- draw.World = &_previewModelWorld;
+ draw.World = &world;
draw.DrawState = &drawState;
draw.Lightmap = nullptr;
draw.LightmapUVs = nullptr;
draw.Flags = StaticFlags::Transform;
draw.DrawModes = (DrawPass)((DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward) & renderContext.View.Pass);
BoundingSphere::FromBox(_previewModelBox, draw.Bounds);
+ draw.Bounds.Center -= renderContext.View.Origin;
draw.PerInstanceRandom = GetPerInstanceRandom();
draw.LODBias = 0;
draw.ForcedLOD = -1;
@@ -288,32 +297,33 @@ void Camera::OnDebugDrawSelected()
void Camera::UpdateCache()
{
- // Update view and projection matrix
- GetMatrices(_view, _projection);
+ // Calculate view and projection matrices
+ Matrix view, projection;
+ GetMatrices(view, projection);
// Update frustum and bounding box
- _frustum.SetMatrix(_view, _projection);
+ _frustum.SetMatrix(view, projection);
_frustum.GetBox(_box);
BoundingSphere::FromBox(_box, _sphere);
#if USE_EDITOR
// Update editor preview model cache
- Matrix rot, world;
- _transform.GetWorld(world);
+ Matrix rot, tmp, world;
+ _transform.GetWorld(tmp);
Matrix::RotationY(PI * -0.5f, rot);
- Matrix::Multiply(rot, world, _previewModelWorld);
+ Matrix::Multiply(rot, tmp, world);
// Calculate snap box for preview model
if (_previewModel && _previewModel->IsLoaded())
{
- _previewModelBox = _previewModel->GetBox(_previewModelWorld);
+ _previewModelBox = _previewModel->GetBox(world);
}
else
{
Vector3 min(-10.0f), max(10.0f);
- min = Vector3::Transform(min, _previewModelWorld);
- max = Vector3::Transform(max, _previewModelWorld);
+ min = Vector3::Transform(min, world);
+ max = Vector3::Transform(max, world);
_previewModelBox = BoundingBox(min, max);
}
diff --git a/Source/Engine/Level/Actors/Camera.h b/Source/Engine/Level/Actors/Camera.h
index 9c380dcfc..2b59ab323 100644
--- a/Source/Engine/Level/Actors/Camera.h
+++ b/Source/Engine/Level/Actors/Camera.h
@@ -35,7 +35,6 @@ API_CLASS(Sealed) class FLAXENGINE_API Camera : public Actor
API_PROPERTY() static Camera* GetMainCamera();
private:
- Matrix _view, _projection;
BoundingFrustum _frustum;
// Camera Settings
@@ -50,27 +49,10 @@ private:
AssetReference _previewModel;
ModelInstanceEntries _previewModelBuffer;
BoundingBox _previewModelBox;
- Matrix _previewModelWorld;
int32 _sceneRenderingKey = -1;
#endif
public:
- ///
- /// Gets the view matrix.
- ///
- API_PROPERTY() FORCE_INLINE Matrix GetView() const
- {
- return _view;
- }
-
- ///
- /// Gets the projection matrix.
- ///
- API_PROPERTY() FORCE_INLINE Matrix GetProjection() const
- {
- return _projection;
- }
-
///
/// Gets the frustum.
///
@@ -218,8 +200,17 @@ public:
///
/// The result camera view matrix.
/// The result camera projection matrix.
- /// The custom output viewport. Use null to skip it.
- API_FUNCTION() virtual void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
+ /// The custom output viewport.
+ API_FUNCTION() void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
+
+ ///
+ /// Calculates the view and the projection matrices for the camera. Support using custom viewport and view origin.
+ ///
+ /// The result camera view matrix.
+ /// The result camera projection matrix.
+ /// The custom output viewport.
+ /// The rendering view origin (for relative-to-camera rendering).
+ API_FUNCTION() void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport, API_PARAM(Ref) const Vector3& origin) const;
#if USE_EDITOR
// Intersection check for editor picking the camera
diff --git a/Source/Engine/Level/Actors/DirectionalLight.cpp b/Source/Engine/Level/Actors/DirectionalLight.cpp
index 5b8d1d51f..59c0213a7 100644
--- a/Source/Engine/Level/Actors/DirectionalLight.cpp
+++ b/Source/Engine/Level/Actors/DirectionalLight.cpp
@@ -18,13 +18,14 @@ void DirectionalLight::Draw(RenderContext& renderContext)
{
float brightness = Brightness;
AdjustBrightness(renderContext.View, brightness);
+ const Float3 position = GetPosition() - renderContext.View.Origin;
if (Brightness > ZeroTolerance
&& (renderContext.View.Flags & ViewFlags::DirectionalLights) != 0
&& renderContext.View.Pass & DrawPass::GBuffer
- && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
+ && (ViewDistance < ZeroTolerance || Float3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererDirectionalLightData data;
- data.Position = GetPosition(); // TODO: large-worlds
+ data.Position = position;
data.MinRoughness = MinRoughness;
data.ShadowsDistance = ShadowsDistance;
data.Color = Color.ToFloat3() * (Color.A * brightness);
diff --git a/Source/Engine/Level/Actors/PointLight.cpp b/Source/Engine/Level/Actors/PointLight.cpp
index 02eb4b517..af0d77e70 100644
--- a/Source/Engine/Level/Actors/PointLight.cpp
+++ b/Source/Engine/Level/Actors/PointLight.cpp
@@ -103,15 +103,16 @@ void PointLight::Draw(RenderContext& renderContext)
{
float brightness = ComputeBrightness();
AdjustBrightness(renderContext.View, brightness);
+ const Float3 position = GetPosition() - renderContext.View.Origin;
const float radius = GetScaledRadius();
if ((renderContext.View.Flags & ViewFlags::PointLights) != 0
&& brightness > ZeroTolerance
&& renderContext.View.Pass & DrawPass::GBuffer
&& radius > ZeroTolerance
- && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
+ && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererPointLightData data;
- data.Position = GetPosition(); // TODO: large-worlds
+ data.Position = position;
data.MinRoughness = MinRoughness;
data.ShadowsDistance = ShadowsDistance;
data.Color = Color.ToFloat3() * (Color.A * brightness);
diff --git a/Source/Engine/Level/Actors/PostFxVolume.cpp b/Source/Engine/Level/Actors/PostFxVolume.cpp
index 9ac6da649..4f46a7236 100644
--- a/Source/Engine/Level/Actors/PostFxVolume.cpp
+++ b/Source/Engine/Level/Actors/PostFxVolume.cpp
@@ -22,7 +22,7 @@ void PostFxVolume::Collect(RenderContext& renderContext)
if (_isBounded)
{
Real distance;
- if (_bounds.Contains(renderContext.View.Position, &distance) == ContainmentType::Contains)
+ if (_bounds.Contains(renderContext.View.WorldPosition, &distance) == ContainmentType::Contains)
{
if (_blendRadius > 0.0f)
weight = Math::Saturate((float)distance / _blendRadius) * weight;
diff --git a/Source/Engine/Level/Actors/SkyLight.cpp b/Source/Engine/Level/Actors/SkyLight.cpp
index 9a86ff704..2261b72bb 100644
--- a/Source/Engine/Level/Actors/SkyLight.cpp
+++ b/Source/Engine/Level/Actors/SkyLight.cpp
@@ -100,13 +100,14 @@ void SkyLight::Draw(RenderContext& renderContext)
{
float brightness = Brightness;
AdjustBrightness(renderContext.View, brightness);
+ const Float3 position = GetPosition() - renderContext.View.Origin;
if ((renderContext.View.Flags & ViewFlags::SkyLights) != 0
&& renderContext.View.Pass & DrawPass::GBuffer
&& brightness > ZeroTolerance
- && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
+ && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererSkyLightData data;
- data.Position = GetPosition(); // TODO: large-worlds
+ data.Position = position;
data.Color = Color.ToFloat3() * (Color.A * brightness);
data.VolumetricScatteringIntensity = VolumetricScatteringIntensity;
data.CastVolumetricShadow = CastVolumetricShadow;
diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp
index 6fc12edd6..f5a5d0f8c 100644
--- a/Source/Engine/Level/Actors/SplineModel.cpp
+++ b/Source/Engine/Level/Actors/SplineModel.cpp
@@ -136,7 +136,7 @@ void SplineModel::OnSplineUpdated()
for (int32 j = 0; j < meshes.Count(); j++)
{
const auto& mesh = meshes[j];
- mesh.GetCorners(corners);
+ mesh.GetBox().GetCorners(corners);
for (int32 i = 0; i < 8; i++)
{
diff --git a/Source/Engine/Level/Actors/SpotLight.cpp b/Source/Engine/Level/Actors/SpotLight.cpp
index a01a6e584..ad69b1502 100644
--- a/Source/Engine/Level/Actors/SpotLight.cpp
+++ b/Source/Engine/Level/Actors/SpotLight.cpp
@@ -151,6 +151,7 @@ void SpotLight::Draw(RenderContext& renderContext)
{
float brightness = ComputeBrightness();
AdjustBrightness(renderContext.View, brightness);
+ const Float3 position = GetPosition() - renderContext.View.Origin;
const float radius = GetScaledRadius();
const float outerConeAngle = GetOuterConeAngle();
if ((renderContext.View.Flags & ViewFlags::SpotLights) != 0
@@ -158,10 +159,10 @@ void SpotLight::Draw(RenderContext& renderContext)
&& brightness > ZeroTolerance
&& radius > ZeroTolerance
&& outerConeAngle > ZeroTolerance
- && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
+ && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererSpotLightData data;
- data.Position = GetPosition(); // TODO: large-worlds
+ data.Position = position;
data.MinRoughness = MinRoughness;
data.ShadowsDistance = ShadowsDistance;
data.Color = Color.ToFloat3() * (Color.A * brightness);
diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp
index 6bb0ed917..85026b05d 100644
--- a/Source/Engine/Level/Actors/StaticModel.cpp
+++ b/Source/Engine/Level/Actors/StaticModel.cpp
@@ -18,7 +18,6 @@
StaticModel::StaticModel(const SpawnParams& params)
: ModelInstanceActor(params)
- , _world(Matrix::Identity)
, _scaleInLightmap(1.0f)
, _boundsScale(1.0f)
, _lodBias(0)
@@ -210,16 +209,9 @@ void StaticModel::UpdateBounds()
{
if (Model && Model->IsLoaded())
{
- Matrix world;
- if (Math::IsOne(_boundsScale))
- world = _world;
- else
- {
- Transform t = _transform;
- t.Scale *= _boundsScale;
- t.GetWorld(world);
- }
- _box = Model->GetBox(world);
+ Transform transform = _transform;
+ transform.Scale *= _boundsScale;
+ _box = Model->GetBox(transform);
}
else
{
@@ -240,17 +232,21 @@ void StaticModel::Draw(RenderContext& renderContext)
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass);
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None)
return;
+
+ Matrix world;
+ renderContext.View.GetWorldMatrix(_transform, world);
+
if (renderContext.View.Pass == DrawPass::GlobalSDF)
{
- GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, _world, _box);
+ GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, world, _box);
return;
}
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
{
- GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _world, Model->LODs.Last().GetBox());
+ GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, world, Model->LODs.Last().GetBox());
return;
}
- GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, _world);
+ GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
// Flush vertex colors if need to
if (_vertexColorsDirty)
@@ -282,18 +278,19 @@ void StaticModel::Draw(RenderContext& renderContext)
#if USE_EDITOR
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
if (!Editor::IsPlayMode)
- _drawState.PrevWorld = _world;
+ _drawState.PrevWorld = world;
#endif
Mesh::DrawInfo draw;
draw.Buffer = &Entries;
- draw.World = &_world;
+ draw.World = &world;
draw.DrawState = &_drawState;
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
draw.LightmapUVs = &Lightmap.UVsArea;
draw.Flags = _staticFlags;
draw.DrawModes = drawModes;
draw.Bounds = _sphere;
+ draw.Bounds.Center -= renderContext.View.Origin;
draw.PerInstanceRandom = GetPerInstanceRandom();
draw.LODBias = _lodBias;
draw.ForcedLOD = _forcedLod;
@@ -301,7 +298,7 @@ void StaticModel::Draw(RenderContext& renderContext)
Model->Draw(renderContext, draw);
- GEOMETRY_DRAW_STATE_EVENT_END(_drawState, _world);
+ GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
}
bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
@@ -311,7 +308,7 @@ bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& norm
if (Model != nullptr && Model->IsLoaded())
{
Mesh* mesh;
- result = Model->Intersects(ray, _world, distance, normal, &mesh);
+ result = Model->Intersects(ray, _transform, distance, normal, &mesh);
}
return result;
@@ -473,7 +470,7 @@ bool StaticModel::IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distan
for (int32 i = 0; i < meshes.Count(); i++)
{
const auto& mesh = meshes[i];
- if (mesh.GetMaterialSlotIndex() == entryIndex && mesh.Intersects(ray, _world, distance, normal))
+ if (mesh.GetMaterialSlotIndex() == entryIndex && mesh.Intersects(ray, _transform, distance, normal))
return true;
}
@@ -500,7 +497,7 @@ bool StaticModel::IntersectsEntry(const Ray& ray, Real& distance, Vector3& norma
const auto& mesh = meshes[i];
Real dst;
Vector3 nrm;
- if (mesh.Intersects(ray, _world, dst, nrm) && dst < closest)
+ if (mesh.Intersects(ray, _transform, dst, nrm) && dst < closest)
{
result = true;
closest = dst;
@@ -520,7 +517,6 @@ void StaticModel::OnTransformChanged()
// Base
ModelInstanceActor::OnTransformChanged();
- _transform.GetWorld(_world);
UpdateBounds();
}
diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h
index 2068c2384..f3c5c4bb5 100644
--- a/Source/Engine/Level/Actors/StaticModel.h
+++ b/Source/Engine/Level/Actors/StaticModel.h
@@ -14,7 +14,6 @@ API_CLASS() class FLAXENGINE_API StaticModel : public ModelInstanceActor
{
DECLARE_SCENE_OBJECT(StaticModel);
private:
- Matrix _world;
GeometryDrawStateData _drawState;
float _scaleInLightmap;
float _boundsScale;
@@ -50,15 +49,6 @@ public:
LightmapEntry Lightmap;
public:
- ///
- /// Gets the model world matrix transform.
- ///
- /// The result world matrix.
- FORCE_INLINE void GetWorld(Matrix* world) const
- {
- *world = _world;
- }
-
///
/// Gets the model scale in lightmap (applied to all the meshes).
///
diff --git a/Source/Engine/Level/LargeWorlds.h b/Source/Engine/Level/LargeWorlds.h
new file mode 100644
index 000000000..56ecb2fb0
--- /dev/null
+++ b/Source/Engine/Level/LargeWorlds.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Engine/Core/Types/BaseTypes.h"
+
+///
+/// The engine utility for large worlds support. Contains constants and tools for using 64-bit precision coordinates in various game systems (eg. scene rendering).
+///
+API_CLASS(Static) class FLAXENGINE_API LargeWorlds
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(LargeWorlds);
+
+ ///
+ /// Enables large worlds usage in the engine. If true, scene rendering and other systems will use origin shifting to achieve higher precision in large worlds.
+ ///
+ API_FIELD() static bool Enable;
+
+ ///
+ /// Defines the size of a single chunk. Large world (64-bit) gets divided into smaller chunks so all the math operations (32-bit) can be performed relative to the chunk origin without precision loss.
+ ///
+ API_FIELD() static constexpr Real ChunkSize = 1024;
+
+ ///
+ /// Updates the large world origin to match the input position. The origin is snapped to the best matching chunk location.
+ ///
+ /// The current origin of teh large world. Gets updated with the input position.
+ /// The current input position (eg. render view location or auto listener position).
+ /// Used only if LargeWorlds::Enabled is true.
+ API_FUNCTION() static void UpdateOrigin(API_PARAM(Ref) Vector3& origin, const Vector3& position);
+};
diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp
index ddcc7797a..0e35e9dac 100644
--- a/Source/Engine/Level/Level.cpp
+++ b/Source/Engine/Level/Level.cpp
@@ -2,6 +2,7 @@
#include "Level.h"
#include "ActorsCache.h"
+#include "LargeWorlds.h"
#include "SceneQuery.h"
#include "SceneObjectsFactory.h"
#include "Scene/Scene.h"
@@ -39,6 +40,19 @@
#include "Engine/Serialization/JsonSerializer.h"
#endif
+#if USE_LARGE_WORLDS
+bool LargeWorlds::Enable = true;
+#else
+bool LargeWorlds::Enable = false;
+#endif
+
+void LargeWorlds::UpdateOrigin(Vector3& origin, const Vector3& position)
+{
+ if (Enable)
+ {
+ }
+}
+
bool LayersMask::HasLayer(const StringView& layerName) const
{
return HasLayer(Level::GetLayerIndex(layerName));
diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp
index affd8e576..8dcde5afc 100644
--- a/Source/Engine/Level/Scene/SceneRendering.cpp
+++ b/Source/Engine/Level/Scene/SceneRendering.cpp
@@ -33,6 +33,7 @@ void SceneRendering::Draw(RenderContext& renderContext)
ScopeLock lock(Locker);
auto& view = renderContext.View;
const BoundingFrustum frustum = view.CullingFrustum;
+ const Vector3 origin = view.Origin;
renderContext.List->Scenes.Add(this);
// Draw all visual components
@@ -40,7 +41,8 @@ void SceneRendering::Draw(RenderContext& renderContext)
{
for (int32 i = 0; i < Actors.Count(); i++)
{
- auto& e = Actors[i];
+ auto e = Actors[i];
+ e.Bounds.Center -= origin;
if (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)) && e.Actor->GetStaticFlags() & view.StaticFlagsMask)
{
#if SCENE_RENDERING_USE_PROFILER
@@ -54,7 +56,8 @@ void SceneRendering::Draw(RenderContext& renderContext)
{
for (int32 i = 0; i < Actors.Count(); i++)
{
- auto& e = Actors[i];
+ auto e = Actors[i];
+ e.Bounds.Center -= origin;
if (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)))
{
#if SCENE_RENDERING_USE_PROFILER
diff --git a/Source/Engine/Physics/Colliders/BoxCollider.cpp b/Source/Engine/Physics/Colliders/BoxCollider.cpp
index d3dcc2295..d4f634f64 100644
--- a/Source/Engine/Physics/Colliders/BoxCollider.cpp
+++ b/Source/Engine/Physics/Colliders/BoxCollider.cpp
@@ -129,7 +129,7 @@ void BoxCollider::UpdateBounds()
{
// Cache bounds
OrientedBoundingBox::CreateCentered(_center, _size, _bounds);
- _bounds.Transform(_transform.GetWorld());
+ _bounds.Transform(_transform);
_bounds.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
}
diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
index c2a51e800..81f030a9a 100644
--- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
+++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
@@ -99,7 +99,7 @@ void CapsuleCollider::UpdateBounds()
// Cache bounds
const float radiusTwice = _radius * 2.0f;
OrientedBoundingBox::CreateCentered(_center, Vector3(_height + radiusTwice, radiusTwice, radiusTwice), _orientedBox);
- _orientedBox.Transform(_transform.GetWorld());
+ _orientedBox.Transform(_transform);
_orientedBox.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
}
diff --git a/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp b/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp
index 7556ac3a3..38e0e1a9b 100644
--- a/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp
+++ b/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp
@@ -5,7 +5,6 @@
#include "Engine/Core/Math/Math.h"
#include "Engine/Level/Actors/BoxBrush.h"
#include "Engine/Level/Actors/StaticModel.h"
-#include "Engine/ContentImporters/ImportTexture.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Level/Level.h"
#include "Engine/Terrain/Terrain.h"
@@ -40,10 +39,6 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC
entry.AsStaticModel.Actor = staticModel;
entry.Scale = Math::Clamp(staticModel->GetScaleInLightmap(), 0.0f, LIGHTMAP_SCALE_MAX);
- // Spawn entry for each mesh
- Matrix world;
- staticModel->GetWorld(&world);
-
// Use the first LOD
const int32 lodIndex = 0;
auto& lod = model->LODs[lodIndex];
@@ -61,18 +56,16 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC
}
else
{
- LOG(Warning, "Model \'{0}\' mesh index {1} (lod: {2}) has missing lightmap UVs (at actor: {3})",
- model->GetPath(),
- meshIndex,
- lodIndex,
- staticModel->GetNamePath());
+ LOG(Warning, "Model \'{0}\' mesh index {1} (lod: {2}) has missing lightmap UVs (at actor: {3})", model->GetPath(), meshIndex, lodIndex, staticModel->GetNamePath());
}
}
}
if (useLightmap && anyValid && entry.Scale > ZeroTolerance)
{
- entry.Box = model->GetBox(world);
+ Matrix worldMatrix;
+ staticModel->GetTransform().GetWorld(worldMatrix);
+ entry.Box = model->GetBox(worldMatrix);
results.Add(entry);
}
else
diff --git a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp
index a6d5de4a8..830298f58 100644
--- a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp
+++ b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp
@@ -124,7 +124,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
auto& lod = staticModel->Model->LODs[0];
Matrix worldMatrix;
- staticModel->GetWorld(&worldMatrix);
+ staticModel->GetTransform().GetWorld(worldMatrix);
Matrix::Transpose(worldMatrix, shaderData.WorldMatrix);
shaderData.LightmapArea = staticModel->Lightmap.UVsArea;
diff --git a/Source/Engine/Terrain/TerrainChunk.cpp b/Source/Engine/Terrain/TerrainChunk.cpp
index b3b63791b..4a6aea948 100644
--- a/Source/Engine/Terrain/TerrainChunk.cpp
+++ b/Source/Engine/Terrain/TerrainChunk.cpp
@@ -189,7 +189,7 @@ void TerrainChunk::UpdateBounds()
{
const Vector3 boundsExtent = _patch->_terrain->_boundsExtent;
const float size = (float)_patch->_terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX;
- Transform terrainTransform = _patch->_terrain->_transform;
+ const Transform terrainTransform = _patch->_terrain->_transform;
Transform localTransform;
localTransform.Translation = _patch->_offset + Vector3(_x * size, _yOffset, _z * size);
@@ -197,11 +197,8 @@ void TerrainChunk::UpdateBounds()
localTransform.Scale = Vector3(size, _yHeight, size);
localTransform = terrainTransform.LocalToWorld(localTransform);
- Matrix world;
- localTransform.GetWorld(world);
-
OrientedBoundingBox obb(Vector3::Zero, Vector3::One);
- obb.Transform(world);
+ obb.Transform(localTransform);
obb.GetBoundingBox(_bounds);
_boundsCenter = _bounds.GetCenter();