Add relative-to-camera rendering for large worlds
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -777,16 +777,16 @@ namespace FlaxEditor.Viewport
|
||||
/// <param name="view">The view.</param>
|
||||
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
|
||||
/// <summary>
|
||||
/// Creates the view matrix.
|
||||
/// </summary>
|
||||
/// <param name="position">The view position.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -134,6 +134,18 @@ public:
|
||||
/// <returns>True whether the two objects intersected</returns>
|
||||
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh, int32 lodIndex = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if there is an intersection between the Model and a Ray in given world using given instance.
|
||||
/// </summary>
|
||||
/// <param name="ray">The ray to test</param>
|
||||
/// <param name="transform">The instance transformation.</param>
|
||||
/// <param name="distance">When the method completes, contains the distance of the intersection (if any valid).</param>
|
||||
/// <param name="normal">When the method completes, contains the intersection surface normal vector (if any valid).</param>
|
||||
/// <param name="mesh">Mesh, or null</param>
|
||||
/// <param name="lodIndex">Level Of Detail index</param>
|
||||
/// <returns>True whether the two objects intersected</returns>
|
||||
bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh, int32 lodIndex = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model bounding box in custom matrix world space.
|
||||
/// </summary>
|
||||
@@ -142,6 +154,17 @@ public:
|
||||
/// <returns>The bounding box.</returns>
|
||||
API_FUNCTION() BoundingBox GetBox(const Matrix& world, int32 lodIndex = 0) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model bounding box in custom transformation.
|
||||
/// </summary>
|
||||
/// <param name="transform">The instance transformation.</param>
|
||||
/// <param name="lodIndex">The Level Of Detail index.</param>
|
||||
/// <returns>The bounding box.</returns>
|
||||
API_FUNCTION() BoundingBox GetBox(const Transform& transform, int32 lodIndex = 0) const
|
||||
{
|
||||
return LODs[lodIndex].GetBox(transform);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model bounding box in local space.
|
||||
/// </summary>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -259,13 +259,14 @@ public:
|
||||
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the eight corners of the bounding box.
|
||||
/// Determines if there is an intersection between the mesh and a ray in given world
|
||||
/// </summary>
|
||||
/// <param name="corners">An array of points representing the eight corners of the bounding box.</param>
|
||||
FORCE_INLINE void GetCorners(Vector3 corners[8]) const
|
||||
{
|
||||
_box.GetCorners(corners);
|
||||
}
|
||||
/// <param name="ray">The ray to test</param>
|
||||
/// <param name="transform">The instance transformation.</param>
|
||||
/// <param name="distance">When the method completes and returns true, contains the distance of the intersection (if any valid).</param>
|
||||
/// <param name="normal">When the method completes, contains the intersection surface normal vector (if any valid).</param>
|
||||
/// <returns>True whether the two objects intersected</returns>
|
||||
bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -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 j = 0; j < Meshes.Count(); j++)
|
||||
{
|
||||
const auto& mesh = Meshes[j];
|
||||
mesh.GetBox().GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
Vector3::Transform(corners[i], world, tmp);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -79,19 +79,29 @@ public:
|
||||
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="ray">The ray to test</param>
|
||||
/// <param name="transform">The instance transformation.</param>
|
||||
/// <param name="distance">When the method completes, contains the distance of the intersection (if any valid).</param>
|
||||
/// <param name="normal">When the method completes, contains the intersection surface normal vector (if any valid).</param>
|
||||
/// <param name="mesh">Mesh, or null</param>
|
||||
/// <returns>True whether the two objects intersected</returns>
|
||||
bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh);
|
||||
|
||||
/// <summary>
|
||||
/// Get model bounding box in transformed world matrix.
|
||||
/// </summary>
|
||||
/// <param name="world">World matrix</param>
|
||||
/// <returns>Bounding box</returns>
|
||||
BoundingBox GetBox(const Matrix& world) const;
|
||||
|
||||
/// <summary>
|
||||
/// Get model bounding box in transformed world for given instance buffer for only one mesh
|
||||
/// Get model bounding box in transformed world.
|
||||
/// </summary>
|
||||
/// <param name="world">World matrix</param>
|
||||
/// <param name="meshIndex">esh index</param>
|
||||
/// <param name="transform">The instance transformation.</param>
|
||||
/// <returns>Bounding box</returns>
|
||||
BoundingBox GetBox(const Matrix& world, int32 meshIndex) const;
|
||||
BoundingBox GetBox(const Transform& transform) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding box combined for all meshes in this model LOD.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -79,31 +79,24 @@ namespace FlaxEngine
|
||||
/// <param name="camera">The camera.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies render view data from the camera.
|
||||
/// </summary>
|
||||
/// <param name="camera">The camera.</param>
|
||||
/// <param name="customViewport">The custom viewport to use for view/projeection matrices override.</param>
|
||||
public void CopyFrom(Camera camera, ref Viewport customViewport)
|
||||
/// <param name="viewport">The custom viewport to use for view/projeection matrices override.</param>
|
||||
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;
|
||||
|
||||
@@ -24,7 +24,17 @@ API_STRUCT() struct FLAXENGINE_API RenderView
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderView);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
API_FIELD() Vector3 Origin = Vector3::Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The global position of the view (Origin+Position).
|
||||
/// </summary>
|
||||
API_FIELD() Vector3 WorldPosition;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the view (relative to the origin).
|
||||
/// </summary>
|
||||
API_FIELD() Float3 Position;
|
||||
|
||||
@@ -264,14 +274,10 @@ public:
|
||||
/// <param name="angle">Camera's FOV angle (in degrees)</param>
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Model> _previewModel;
|
||||
ModelInstanceEntries _previewModelBuffer;
|
||||
BoundingBox _previewModelBox;
|
||||
Matrix _previewModelWorld;
|
||||
int32 _sceneRenderingKey = -1;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the view matrix.
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE Matrix GetView() const
|
||||
{
|
||||
return _view;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the projection matrix.
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE Matrix GetProjection() const
|
||||
{
|
||||
return _projection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the frustum.
|
||||
/// </summary>
|
||||
@@ -218,8 +200,17 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="view">The result camera view matrix.</param>
|
||||
/// <param name="projection">The result camera projection matrix.</param>
|
||||
/// <param name="viewport">The custom output viewport. Use null to skip it.</param>
|
||||
API_FUNCTION() virtual void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
|
||||
/// <param name="viewport">The custom output viewport.</param>
|
||||
API_FUNCTION() void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the view and the projection matrices for the camera. Support using custom viewport and view origin.
|
||||
/// </summary>
|
||||
/// <param name="view">The result camera view matrix.</param>
|
||||
/// <param name="projection">The result camera projection matrix.</param>
|
||||
/// <param name="viewport">The custom output viewport.</param>
|
||||
/// <param name="origin">The rendering view origin (for relative-to-camera rendering).</param>
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
/// <summary>
|
||||
/// Gets the model world matrix transform.
|
||||
/// </summary>
|
||||
/// <param name="world">The result world matrix.</param>
|
||||
FORCE_INLINE void GetWorld(Matrix* world) const
|
||||
{
|
||||
*world = _world;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model scale in lightmap (applied to all the meshes).
|
||||
/// </summary>
|
||||
|
||||
31
Source/Engine/Level/LargeWorlds.h
Normal file
31
Source/Engine/Level/LargeWorlds.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
|
||||
/// <summary>
|
||||
/// The engine utility for large worlds support. Contains constants and tools for using 64-bit precision coordinates in various game systems (eg. scene rendering).
|
||||
/// </summary>
|
||||
API_CLASS(Static) class FLAXENGINE_API LargeWorlds
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(LargeWorlds);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
API_FIELD() static bool Enable;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
API_FIELD() static constexpr Real ChunkSize = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Updates the large world origin to match the input position. The origin is snapped to the best matching chunk location.
|
||||
/// </summary>
|
||||
/// <param name="origin">The current origin of teh large world. Gets updated with the input position.</param>
|
||||
/// <param name="position">The current input position (eg. render view location or auto listener position).</param>
|
||||
/// <remarks>Used only if LargeWorlds::Enabled is true.</remarks>
|
||||
API_FUNCTION() static void UpdateOrigin(API_PARAM(Ref) Vector3& origin, const Vector3& position);
|
||||
};
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user