Add relative-to-camera rendering for large worlds
This commit is contained in:
@@ -80,9 +80,10 @@ struct GeometryLookup
|
|||||||
PROFILE_CPU_NAMED("StaticModel");
|
PROFILE_CPU_NAMED("StaticModel");
|
||||||
|
|
||||||
// Check model meshes
|
// Check model meshes
|
||||||
Matrix world;
|
Transform transform = staticModel->GetTransform();
|
||||||
staticModel->GetWorld(&world);
|
Matrix worldMatrix;
|
||||||
const bool isDeterminantPositive = staticModel->GetTransform().GetDeterminant() >= 0.0f;
|
transform.GetWorld(worldMatrix);
|
||||||
|
const bool isDeterminantPositive = transform.GetDeterminant() >= 0.0f;
|
||||||
auto& lod = staticModel->Model->LODs[0];
|
auto& lod = staticModel->Model->LODs[0];
|
||||||
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
|
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
|
||||||
{
|
{
|
||||||
@@ -96,9 +97,9 @@ struct GeometryLookup
|
|||||||
|
|
||||||
// Transform triangle vertices from mesh space to world space
|
// Transform triangle vertices from mesh space to world space
|
||||||
Vector3 t0, t1, t2;
|
Vector3 t0, t1, t2;
|
||||||
Vector3::Transform(t.V0, world, t0);
|
Vector3::Transform(t.V0, worldMatrix, t0);
|
||||||
Vector3::Transform(t.V1, world, t1);
|
Vector3::Transform(t.V1, worldMatrix, t1);
|
||||||
Vector3::Transform(t.V2, world, t2);
|
Vector3::Transform(t.V2, worldMatrix, t2);
|
||||||
|
|
||||||
// Check if triangles intersects with the brush
|
// Check if triangles intersects with the brush
|
||||||
if (CollisionsHelper::SphereIntersectsTriangle(brush, t0, t1, t2))
|
if (CollisionsHelper::SphereIntersectsTriangle(brush, t0, t1, t2))
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
|
|||||||
Matrix m1, m2, world;
|
Matrix m1, m2, world;
|
||||||
for (Actor* icon : icons)
|
for (Actor* icon : icons)
|
||||||
{
|
{
|
||||||
BoundingSphere sphere(icon->GetPosition(), ICON_RADIUS);
|
BoundingSphere sphere(icon->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
|
||||||
IconTypes iconType;
|
IconTypes iconType;
|
||||||
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(icon->GetTypeHandle(), iconType))
|
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(icon->GetTypeHandle(), iconType))
|
||||||
{
|
{
|
||||||
@@ -120,7 +120,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
|
|||||||
auto& view = renderContext.View;
|
auto& view = renderContext.View;
|
||||||
const BoundingFrustum frustum = view.Frustum;
|
const BoundingFrustum frustum = view.Frustum;
|
||||||
Matrix m1, m2, world;
|
Matrix m1, m2, world;
|
||||||
BoundingSphere sphere(actor->GetPosition(), ICON_RADIUS);
|
BoundingSphere sphere(actor->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
|
||||||
IconTypes iconType;
|
IconTypes iconType;
|
||||||
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType))
|
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -777,16 +777,16 @@ namespace FlaxEditor.Viewport
|
|||||||
/// <param name="view">The view.</param>
|
/// <param name="view">The view.</param>
|
||||||
public void CopyViewData(ref RenderView view)
|
public void CopyViewData(ref RenderView view)
|
||||||
{
|
{
|
||||||
// Create matrices
|
Vector3 position = ViewPosition;
|
||||||
CreateProjectionMatrix(out view.Projection);
|
LargeWorlds.UpdateOrigin(ref view.Origin, position);
|
||||||
CreateViewMatrix(out view.View);
|
view.Position = position - view.Origin;
|
||||||
|
|
||||||
// Copy data
|
|
||||||
view.Position = ViewPosition;
|
|
||||||
view.Direction = ViewDirection;
|
view.Direction = ViewDirection;
|
||||||
view.Near = _nearPlane;
|
view.Near = _nearPlane;
|
||||||
view.Far = _farPlane;
|
view.Far = _farPlane;
|
||||||
|
|
||||||
|
CreateProjectionMatrix(out view.Projection);
|
||||||
|
CreateViewMatrix(view.Position, out view.View);
|
||||||
|
|
||||||
view.UpdateCachedData();
|
view.UpdateCachedData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,10 +828,10 @@ namespace FlaxEditor.Viewport
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the view matrix.
|
/// Creates the view matrix.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="position">The view position.</param>
|
||||||
/// <param name="result">The result.</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 direction = ViewDirection;
|
||||||
var target = position + direction;
|
var target = position + direction;
|
||||||
var right = Float3.Normalize(Float3.Cross(Float3.Up, direction));
|
var right = Float3.Normalize(Float3.Cross(Float3.Up, direction));
|
||||||
@@ -862,7 +862,7 @@ namespace FlaxEditor.Viewport
|
|||||||
// Prepare
|
// Prepare
|
||||||
var viewport = new FlaxEngine.Viewport(0, 0, Width, Height);
|
var viewport = new FlaxEngine.Viewport(0, 0, Width, Height);
|
||||||
CreateProjectionMatrix(out var p);
|
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);
|
Matrix.Multiply(ref v, ref p, out var ivp);
|
||||||
ivp.Invert();
|
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);
|
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
|
BoundingBox Model::GetBox(const Matrix& world, int32 lodIndex) const
|
||||||
{
|
{
|
||||||
return LODs[lodIndex].GetBox(world);
|
return LODs[lodIndex].GetBox(world);
|
||||||
|
|||||||
@@ -134,6 +134,18 @@ public:
|
|||||||
/// <returns>True whether the two objects intersected</returns>
|
/// <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);
|
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>
|
/// <summary>
|
||||||
/// Gets the model bounding box in custom matrix world space.
|
/// Gets the model bounding box in custom matrix world space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -142,6 +154,17 @@ public:
|
|||||||
/// <returns>The bounding box.</returns>
|
/// <returns>The bounding box.</returns>
|
||||||
API_FUNCTION() BoundingBox GetBox(const Matrix& world, int32 lodIndex = 0) const;
|
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>
|
/// <summary>
|
||||||
/// Gets the model bounding box in local space.
|
/// Gets the model bounding box in local space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -134,8 +134,7 @@ float BoundingFrustum::GetHeightAtDepth(float depth) const
|
|||||||
ContainmentType BoundingFrustum::Contains(const Vector3& point) const
|
ContainmentType BoundingFrustum::Contains(const Vector3& point) const
|
||||||
{
|
{
|
||||||
PlaneIntersectionType result = PlaneIntersectionType::Front;
|
PlaneIntersectionType result = PlaneIntersectionType::Front;
|
||||||
PlaneIntersectionType planeResult = PlaneIntersectionType::Front;
|
for (int32 i = 0; i < 6; i++)
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
{
|
||||||
const PlaneIntersectionType planeResult = _planes[i].Intersects(point);
|
const PlaneIntersectionType planeResult = _planes[i].Intersects(point);
|
||||||
switch (planeResult)
|
switch (planeResult)
|
||||||
@@ -159,7 +158,7 @@ ContainmentType BoundingFrustum::Contains(const Vector3& point) const
|
|||||||
ContainmentType BoundingFrustum::Contains(const BoundingSphere& sphere) const
|
ContainmentType BoundingFrustum::Contains(const BoundingSphere& sphere) const
|
||||||
{
|
{
|
||||||
auto result = PlaneIntersectionType::Front;
|
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);
|
const PlaneIntersectionType planeResult = _planes[i].Intersects(sphere);
|
||||||
switch (planeResult)
|
switch (planeResult)
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ void Foliage::AddInstance(const FoliageInstance& instance)
|
|||||||
auto& meshes = type->Model->LODs[0].Meshes;
|
auto& meshes = type->Model->LODs[0].Meshes;
|
||||||
for (int32 j = 0; j < meshes.Count(); j++)
|
for (int32 j = 0; j < meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
meshes[j].GetCorners(corners);
|
meshes[j].GetBox().GetCorners(corners);
|
||||||
|
|
||||||
for (int32 k = 0; k < 8; k++)
|
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;
|
auto& meshes = type->Model->LODs[0].Meshes;
|
||||||
for (int32 j = 0; j < meshes.Count(); j++)
|
for (int32 j = 0; j < meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
meshes[j].GetCorners(corners);
|
meshes[j].GetBox().GetCorners(corners);
|
||||||
|
|
||||||
for (int32 k = 0; k < 8; k++)
|
for (int32 k = 0; k < 8; k++)
|
||||||
{
|
{
|
||||||
@@ -512,7 +512,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index)
|
|||||||
for (int32 j = 0; j < meshes.Count(); j++)
|
for (int32 j = 0; j < meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
// TODO: cache bounds for all model meshes and reuse later
|
// TODO: cache bounds for all model meshes and reuse later
|
||||||
meshes[j].GetCorners(corners);
|
meshes[j].GetBox().GetCorners(corners);
|
||||||
|
|
||||||
// TODO: use SIMD
|
// TODO: use SIMD
|
||||||
for (int32 k = 0; k < 8; k++)
|
for (int32 k = 0; k < 8; k++)
|
||||||
@@ -1282,7 +1282,7 @@ void Foliage::OnTransformChanged()
|
|||||||
auto& meshes = type->Model->LODs[0].Meshes;
|
auto& meshes = type->Model->LODs[0].Meshes;
|
||||||
for (int32 j = 0; j < meshes.Count(); j++)
|
for (int32 j = 0; j < meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
meshes[j].GetCorners(corners);
|
meshes[j].GetBox().GetCorners(corners);
|
||||||
|
|
||||||
for (int32 k = 0; k < 8; k++)
|
for (int32 k = 0; k < 8; k++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Engine/Core/Math/Vector3.h"
|
#include "Engine/Core/Math/Vector3.h"
|
||||||
|
#include "Engine/Core/Math/Transform.h"
|
||||||
#include "Engine/Core/Math/Ray.h"
|
#include "Engine/Core/Math/Ray.h"
|
||||||
#include "Engine/Core/Math/CollisionsHelper.h"
|
#include "Engine/Core/Math/CollisionsHelper.h"
|
||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
@@ -74,4 +75,26 @@ public:
|
|||||||
}
|
}
|
||||||
return false;
|
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 "ModelInstanceEntry.h"
|
||||||
#include "Engine/Content/Assets/Material.h"
|
#include "Engine/Content/Assets/Material.h"
|
||||||
#include "Engine/Content/Assets/Model.h"
|
#include "Engine/Content/Assets/Model.h"
|
||||||
|
#include "Engine/Core/Math/Transform.h"
|
||||||
#include "Engine/Graphics/GPUContext.h"
|
#include "Engine/Graphics/GPUContext.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
#include "Engine/Graphics/RenderTask.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
|
// Get bounding box of the mesh bounds transformed by the instance world matrix
|
||||||
Vector3 corners[8];
|
Vector3 corners[8];
|
||||||
GetCorners(corners);
|
_box.GetCorners(corners);
|
||||||
Vector3 tmp;
|
Vector3 tmp;
|
||||||
Vector3::Transform(corners[0], world, tmp);
|
Vector3::Transform(corners[0], world, tmp);
|
||||||
Vector3 min = 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
|
// Use exact test on raw geometry
|
||||||
return _collisionProxy.Intersects(ray, world, distance, normal);
|
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;
|
distance = 0;
|
||||||
normal = Vector3::Up;
|
normal = Vector3::Up;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -259,13 +259,14 @@ public:
|
|||||||
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const;
|
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="corners">An array of points representing the eight corners of the bounding box.</param>
|
/// <param name="ray">The ray to test</param>
|
||||||
FORCE_INLINE void GetCorners(Vector3 corners[8]) const
|
/// <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>
|
||||||
_box.GetCorners(corners);
|
/// <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:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "ModelLOD.h"
|
#include "ModelLOD.h"
|
||||||
|
#include "Engine/Core/Math/Transform.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.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)
|
bool ModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh)
|
||||||
{
|
{
|
||||||
// Check all meshes
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
Real closest = MAX_Real;
|
Real closest = MAX_Real;
|
||||||
Vector3 closestNormal = Vector3::Up;
|
Vector3 closestNormal = Vector3::Up;
|
||||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||||
{
|
{
|
||||||
// Test intersection with mesh and check if is closer than previous
|
|
||||||
Real dst;
|
Real dst;
|
||||||
Vector3 nrm;
|
Vector3 nrm;
|
||||||
if (Meshes[i].Intersects(ray, world, dst, nrm) && dst < closest)
|
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;
|
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;
|
distance = closest;
|
||||||
normal = closestNormal;
|
normal = closestNormal;
|
||||||
return result;
|
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
|
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 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||||
Vector3 corners[8];
|
Vector3 corners[8];
|
||||||
for (int32 j = 0; j < Meshes.Count(); j++)
|
for (int32 j = 0; j < Meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
const auto& mesh = Meshes[j];
|
const auto& mesh = Meshes[j];
|
||||||
mesh.GetCorners(corners);
|
mesh.GetBox().GetCorners(corners);
|
||||||
|
|
||||||
for (int32 i = 0; i < 8; i++)
|
for (int32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
Vector3::Transform(corners[i], world, tmp);
|
Vector3::Transform(corners[i], world, tmp);
|
||||||
@@ -100,42 +118,39 @@ BoundingBox ModelLOD::GetBox(const Matrix& world) const
|
|||||||
max = Vector3::Max(max, tmp);
|
max = Vector3::Max(max, tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BoundingBox(min, max);
|
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 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||||
Vector3 corners[8];
|
Vector3 corners[8];
|
||||||
const auto& mesh = Meshes[meshIndex];
|
for (int32 j = 0; j < Meshes.Count(); j++)
|
||||||
mesh.GetCorners(corners);
|
{
|
||||||
|
const auto& mesh = Meshes[j];
|
||||||
|
mesh.GetBox().GetCorners(corners);
|
||||||
for (int32 i = 0; i < 8; i++)
|
for (int32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
Vector3::Transform(corners[i], world, tmp);
|
transform.LocalToWorld(corners[i], tmp);
|
||||||
min = Vector3::Min(min, tmp);
|
min = Vector3::Min(min, tmp);
|
||||||
max = Vector3::Max(max, tmp);
|
max = Vector3::Max(max, tmp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return BoundingBox(min, max);
|
return BoundingBox(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox ModelLOD::GetBox() const
|
BoundingBox ModelLOD::GetBox() const
|
||||||
{
|
{
|
||||||
// Find minimum and maximum points of the mesh in given world
|
|
||||||
Vector3 min = Vector3::Maximum, max = Vector3::Minimum;
|
Vector3 min = Vector3::Maximum, max = Vector3::Minimum;
|
||||||
Vector3 corners[8];
|
Vector3 corners[8];
|
||||||
for (int32 j = 0; j < Meshes.Count(); j++)
|
for (int32 j = 0; j < Meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
Meshes[j].GetCorners(corners);
|
Meshes[j].GetBox().GetCorners(corners);
|
||||||
|
|
||||||
for (int32 i = 0; i < 8; i++)
|
for (int32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
min = Vector3::Min(min, corners[i]);
|
min = Vector3::Min(min, corners[i]);
|
||||||
max = Vector3::Max(max, corners[i]);
|
max = Vector3::Max(max, corners[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BoundingBox(min, max);
|
return BoundingBox(min, max);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,19 +79,29 @@ public:
|
|||||||
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh);
|
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="world">World matrix</param>
|
/// <param name="world">World matrix</param>
|
||||||
/// <returns>Bounding box</returns>
|
/// <returns>Bounding box</returns>
|
||||||
BoundingBox GetBox(const Matrix& world) const;
|
BoundingBox GetBox(const Matrix& world) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get model bounding box in transformed world for given instance buffer for only one mesh
|
/// Get model bounding box in transformed world.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="world">World matrix</param>
|
/// <param name="transform">The instance transformation.</param>
|
||||||
/// <param name="meshIndex">esh index</param>
|
|
||||||
/// <returns>Bounding box</returns>
|
/// <returns>Bounding box</returns>
|
||||||
BoundingBox GetBox(const Matrix& world, int32 meshIndex) const;
|
BoundingBox GetBox(const Transform& transform) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the bounding box combined for all meshes in this model LOD.
|
/// Gets the bounding box combined for all meshes in this model LOD.
|
||||||
|
|||||||
@@ -255,6 +255,9 @@ void SceneRenderTask::ClearCustomActors()
|
|||||||
|
|
||||||
void SceneRenderTask::CollectPostFxVolumes(RenderContext& renderContext)
|
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)
|
if ((ActorsSource & ActorsSources::Scenes) != 0)
|
||||||
{
|
{
|
||||||
Level::CollectPostFxVolumes(renderContext);
|
Level::CollectPostFxVolumes(renderContext);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "RenderView.h"
|
#include "RenderView.h"
|
||||||
|
#include "Engine/Level/LargeWorlds.h"
|
||||||
#include "Engine/Level/Actors/Camera.h"
|
#include "Engine/Level/Actors/Camera.h"
|
||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
#include "Engine/Renderer/RendererPass.h"
|
#include "Engine/Renderer/RendererPass.h"
|
||||||
@@ -70,6 +71,8 @@ void RenderView::PrepareCache(RenderContext& renderContext, float width, float h
|
|||||||
TemporalAAJitter.X = temporalAAJitter.X;
|
TemporalAAJitter.X = temporalAAJitter.X;
|
||||||
TemporalAAJitter.Y = temporalAAJitter.Y;
|
TemporalAAJitter.Y = temporalAAJitter.Y;
|
||||||
|
|
||||||
|
WorldPosition = Origin + Position;
|
||||||
|
|
||||||
// Ortho views have issues with screen size LOD culling
|
// Ortho views have issues with screen size LOD culling
|
||||||
const float modelLODDistanceFactor = (renderContext.LodProxyView ? renderContext.LodProxyView->IsOrthographicProjection() : IsOrthographicProjection()) ? 100.0f : ModelLODDistanceFactor;
|
const float modelLODDistanceFactor = (renderContext.LodProxyView ? renderContext.LodProxyView->IsOrthographicProjection() : IsOrthographicProjection()) ? 100.0f : ModelLODDistanceFactor;
|
||||||
ModelLODDistanceFactorSqrt = modelLODDistanceFactor * modelLODDistanceFactor;
|
ModelLODDistanceFactorSqrt = modelLODDistanceFactor * modelLODDistanceFactor;
|
||||||
@@ -161,31 +164,15 @@ void RenderView::SetProjector(float nearPlane, float farPlane, const Float3& pos
|
|||||||
CullingFrustum = Frustum;
|
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)
|
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();
|
Direction = camera->GetDirection();
|
||||||
Near = camera->GetNearPlane();
|
Near = camera->GetNearPlane();
|
||||||
Far = camera->GetFarPlane();
|
Far = camera->GetFarPlane();
|
||||||
View = camera->GetView();
|
camera->GetMatrices(View, Projection, viewport ? *viewport : camera->GetViewport(), Origin);
|
||||||
camera->GetMatrices(View, Projection, *viewport);
|
|
||||||
Frustum.SetMatrix(View, Projection);
|
Frustum.SetMatrix(View, Projection);
|
||||||
NonJitteredProjection = Projection;
|
NonJitteredProjection = Projection;
|
||||||
Matrix::Invert(View, IV);
|
Matrix::Invert(View, IV);
|
||||||
@@ -211,3 +198,9 @@ DrawPass RenderView::GetShadowsDrawPassMask(ShadowsCastingMode shadowsMode) cons
|
|||||||
return DrawPass::All;
|
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>
|
/// <param name="camera">The camera.</param>
|
||||||
public void CopyFrom(Camera camera)
|
public void CopyFrom(Camera camera)
|
||||||
{
|
{
|
||||||
Position = camera.Position;
|
var viewport = camera.Viewport;
|
||||||
Direction = camera.Direction;
|
CopyFrom(camera, ref viewport);
|
||||||
Near = camera.NearPlane;
|
|
||||||
Far = camera.FarPlane;
|
|
||||||
View = camera.View;
|
|
||||||
Projection = camera.Projection;
|
|
||||||
NonJitteredProjection = Projection;
|
|
||||||
TemporalAAJitter = Float4.Zero;
|
|
||||||
RenderLayersMask = camera.RenderLayersMask;
|
|
||||||
|
|
||||||
UpdateCachedData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies render view data from the camera.
|
/// Copies render view data from the camera.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="camera">The camera.</param>
|
/// <param name="camera">The camera.</param>
|
||||||
/// <param name="customViewport">The custom viewport to use for view/projeection matrices override.</param>
|
/// <param name="viewport">The custom viewport to use for view/projeection matrices override.</param>
|
||||||
public void CopyFrom(Camera camera, ref Viewport customViewport)
|
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;
|
Direction = camera.Direction;
|
||||||
Near = camera.NearPlane;
|
Near = camera.NearPlane;
|
||||||
Far = camera.FarPlane;
|
Far = camera.FarPlane;
|
||||||
camera.GetMatrices(out View, out Projection, ref customViewport);
|
camera.GetMatrices(out View, out Projection, ref viewport, ref Origin);
|
||||||
NonJitteredProjection = Projection;
|
NonJitteredProjection = Projection;
|
||||||
TemporalAAJitter = Float4.Zero;
|
TemporalAAJitter = Float4.Zero;
|
||||||
RenderLayersMask = camera.RenderLayersMask;
|
RenderLayersMask = camera.RenderLayersMask;
|
||||||
|
|||||||
@@ -24,7 +24,17 @@ API_STRUCT() struct FLAXENGINE_API RenderView
|
|||||||
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderView);
|
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderView);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
API_FIELD() Float3 Position;
|
API_FIELD() Float3 Position;
|
||||||
|
|
||||||
@@ -264,14 +274,10 @@ public:
|
|||||||
/// <param name="angle">Camera's FOV angle (in degrees)</param>
|
/// <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);
|
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
|
// Copy view data from camera
|
||||||
// @param camera Camera to copy its data
|
// @param camera Camera to copy its data
|
||||||
// @param camera The custom viewport to use for view/projection matrices override.
|
// @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:
|
public:
|
||||||
DrawPass GetShadowsDrawPassMask(ShadowsCastingMode shadowsMode) const;
|
DrawPass GetShadowsDrawPassMask(ShadowsCastingMode shadowsMode) const;
|
||||||
@@ -288,4 +294,7 @@ public:
|
|||||||
{
|
{
|
||||||
return Frustum.GetMatrix();
|
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;
|
const auto prevBounds = _box;
|
||||||
_size = value;
|
_size = value;
|
||||||
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
|
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
|
||||||
_bounds.Transform(_transform.GetWorld());
|
_bounds.Transform(_transform);
|
||||||
_bounds.GetBoundingBox(_box);
|
_bounds.GetBoundingBox(_box);
|
||||||
BoundingSphere::FromBox(_box, _sphere);
|
BoundingSphere::FromBox(_box, _sphere);
|
||||||
OnBoundsChanged(prevBounds);
|
OnBoundsChanged(prevBounds);
|
||||||
@@ -142,7 +142,7 @@ void BoxVolume::OnTransformChanged()
|
|||||||
|
|
||||||
const auto prevBounds = _box;
|
const auto prevBounds = _box;
|
||||||
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
|
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
|
||||||
_bounds.Transform(_transform.GetWorld());
|
_bounds.Transform(_transform);
|
||||||
_bounds.GetBoundingBox(_box);
|
_bounds.GetBoundingBox(_box);
|
||||||
BoundingSphere::FromBox(_box, _sphere);
|
BoundingSphere::FromBox(_box, _sphere);
|
||||||
OnBoundsChanged(prevBounds);
|
OnBoundsChanged(prevBounds);
|
||||||
|
|||||||
@@ -189,10 +189,15 @@ Viewport Camera::GetViewport() const
|
|||||||
|
|
||||||
void Camera::GetMatrices(Matrix& view, Matrix& projection) 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
|
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
|
// Create projection matrix
|
||||||
if (_usePerspective)
|
if (_usePerspective)
|
||||||
@@ -207,10 +212,11 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp
|
|||||||
|
|
||||||
// Create view matrix
|
// Create view matrix
|
||||||
const Float3 direction = GetDirection();
|
const Float3 direction = GetDirection();
|
||||||
const Vector3 target = _transform.Translation + direction;
|
const Float3 position = _transform.Translation - origin;
|
||||||
Vector3 up;
|
const Float3 target = position + direction;
|
||||||
Vector3::Transform(Vector3::Up, GetOrientation(), up);
|
Float3 up;
|
||||||
Matrix::LookAt(_transform.Translation, target, up, view);
|
Float3::Transform(Float3::Up, GetOrientation(), up);
|
||||||
|
Matrix::LookAt(position, target, up, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -253,16 +259,19 @@ void Camera::Draw(RenderContext& renderContext)
|
|||||||
&& _previewModel
|
&& _previewModel
|
||||||
&& _previewModel->IsLoaded())
|
&& _previewModel->IsLoaded())
|
||||||
{
|
{
|
||||||
|
Matrix world;
|
||||||
|
renderContext.View.GetWorldMatrix(_transform, world);
|
||||||
GeometryDrawStateData drawState;
|
GeometryDrawStateData drawState;
|
||||||
Mesh::DrawInfo draw;
|
Mesh::DrawInfo draw;
|
||||||
draw.Buffer = &_previewModelBuffer;
|
draw.Buffer = &_previewModelBuffer;
|
||||||
draw.World = &_previewModelWorld;
|
draw.World = &world;
|
||||||
draw.DrawState = &drawState;
|
draw.DrawState = &drawState;
|
||||||
draw.Lightmap = nullptr;
|
draw.Lightmap = nullptr;
|
||||||
draw.LightmapUVs = nullptr;
|
draw.LightmapUVs = nullptr;
|
||||||
draw.Flags = StaticFlags::Transform;
|
draw.Flags = StaticFlags::Transform;
|
||||||
draw.DrawModes = (DrawPass)((DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward) & renderContext.View.Pass);
|
draw.DrawModes = (DrawPass)((DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward) & renderContext.View.Pass);
|
||||||
BoundingSphere::FromBox(_previewModelBox, draw.Bounds);
|
BoundingSphere::FromBox(_previewModelBox, draw.Bounds);
|
||||||
|
draw.Bounds.Center -= renderContext.View.Origin;
|
||||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||||
draw.LODBias = 0;
|
draw.LODBias = 0;
|
||||||
draw.ForcedLOD = -1;
|
draw.ForcedLOD = -1;
|
||||||
@@ -288,32 +297,33 @@ void Camera::OnDebugDrawSelected()
|
|||||||
|
|
||||||
void Camera::UpdateCache()
|
void Camera::UpdateCache()
|
||||||
{
|
{
|
||||||
// Update view and projection matrix
|
// Calculate view and projection matrices
|
||||||
GetMatrices(_view, _projection);
|
Matrix view, projection;
|
||||||
|
GetMatrices(view, projection);
|
||||||
|
|
||||||
// Update frustum and bounding box
|
// Update frustum and bounding box
|
||||||
_frustum.SetMatrix(_view, _projection);
|
_frustum.SetMatrix(view, projection);
|
||||||
_frustum.GetBox(_box);
|
_frustum.GetBox(_box);
|
||||||
BoundingSphere::FromBox(_box, _sphere);
|
BoundingSphere::FromBox(_box, _sphere);
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
// Update editor preview model cache
|
// Update editor preview model cache
|
||||||
Matrix rot, world;
|
Matrix rot, tmp, world;
|
||||||
_transform.GetWorld(world);
|
_transform.GetWorld(tmp);
|
||||||
Matrix::RotationY(PI * -0.5f, rot);
|
Matrix::RotationY(PI * -0.5f, rot);
|
||||||
Matrix::Multiply(rot, world, _previewModelWorld);
|
Matrix::Multiply(rot, tmp, world);
|
||||||
|
|
||||||
// Calculate snap box for preview model
|
// Calculate snap box for preview model
|
||||||
if (_previewModel && _previewModel->IsLoaded())
|
if (_previewModel && _previewModel->IsLoaded())
|
||||||
{
|
{
|
||||||
_previewModelBox = _previewModel->GetBox(_previewModelWorld);
|
_previewModelBox = _previewModel->GetBox(world);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector3 min(-10.0f), max(10.0f);
|
Vector3 min(-10.0f), max(10.0f);
|
||||||
min = Vector3::Transform(min, _previewModelWorld);
|
min = Vector3::Transform(min, world);
|
||||||
max = Vector3::Transform(max, _previewModelWorld);
|
max = Vector3::Transform(max, world);
|
||||||
_previewModelBox = BoundingBox(min, max);
|
_previewModelBox = BoundingBox(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ API_CLASS(Sealed) class FLAXENGINE_API Camera : public Actor
|
|||||||
API_PROPERTY() static Camera* GetMainCamera();
|
API_PROPERTY() static Camera* GetMainCamera();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Matrix _view, _projection;
|
|
||||||
BoundingFrustum _frustum;
|
BoundingFrustum _frustum;
|
||||||
|
|
||||||
// Camera Settings
|
// Camera Settings
|
||||||
@@ -50,27 +49,10 @@ private:
|
|||||||
AssetReference<Model> _previewModel;
|
AssetReference<Model> _previewModel;
|
||||||
ModelInstanceEntries _previewModelBuffer;
|
ModelInstanceEntries _previewModelBuffer;
|
||||||
BoundingBox _previewModelBox;
|
BoundingBox _previewModelBox;
|
||||||
Matrix _previewModelWorld;
|
|
||||||
int32 _sceneRenderingKey = -1;
|
int32 _sceneRenderingKey = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
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>
|
/// <summary>
|
||||||
/// Gets the frustum.
|
/// Gets the frustum.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -218,8 +200,17 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="view">The result camera view matrix.</param>
|
/// <param name="view">The result camera view matrix.</param>
|
||||||
/// <param name="projection">The result camera projection matrix.</param>
|
/// <param name="projection">The result camera projection matrix.</param>
|
||||||
/// <param name="viewport">The custom output viewport. Use null to skip it.</param>
|
/// <param name="viewport">The custom output viewport.</param>
|
||||||
API_FUNCTION() virtual void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
|
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
|
#if USE_EDITOR
|
||||||
// Intersection check for editor picking the camera
|
// Intersection check for editor picking the camera
|
||||||
|
|||||||
@@ -18,13 +18,14 @@ void DirectionalLight::Draw(RenderContext& renderContext)
|
|||||||
{
|
{
|
||||||
float brightness = Brightness;
|
float brightness = Brightness;
|
||||||
AdjustBrightness(renderContext.View, brightness);
|
AdjustBrightness(renderContext.View, brightness);
|
||||||
|
const Float3 position = GetPosition() - renderContext.View.Origin;
|
||||||
if (Brightness > ZeroTolerance
|
if (Brightness > ZeroTolerance
|
||||||
&& (renderContext.View.Flags & ViewFlags::DirectionalLights) != 0
|
&& (renderContext.View.Flags & ViewFlags::DirectionalLights) != 0
|
||||||
&& renderContext.View.Pass & DrawPass::GBuffer
|
&& 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;
|
RendererDirectionalLightData data;
|
||||||
data.Position = GetPosition(); // TODO: large-worlds
|
data.Position = position;
|
||||||
data.MinRoughness = MinRoughness;
|
data.MinRoughness = MinRoughness;
|
||||||
data.ShadowsDistance = ShadowsDistance;
|
data.ShadowsDistance = ShadowsDistance;
|
||||||
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
||||||
|
|||||||
@@ -103,15 +103,16 @@ void PointLight::Draw(RenderContext& renderContext)
|
|||||||
{
|
{
|
||||||
float brightness = ComputeBrightness();
|
float brightness = ComputeBrightness();
|
||||||
AdjustBrightness(renderContext.View, brightness);
|
AdjustBrightness(renderContext.View, brightness);
|
||||||
|
const Float3 position = GetPosition() - renderContext.View.Origin;
|
||||||
const float radius = GetScaledRadius();
|
const float radius = GetScaledRadius();
|
||||||
if ((renderContext.View.Flags & ViewFlags::PointLights) != 0
|
if ((renderContext.View.Flags & ViewFlags::PointLights) != 0
|
||||||
&& brightness > ZeroTolerance
|
&& brightness > ZeroTolerance
|
||||||
&& renderContext.View.Pass & DrawPass::GBuffer
|
&& renderContext.View.Pass & DrawPass::GBuffer
|
||||||
&& radius > ZeroTolerance
|
&& radius > ZeroTolerance
|
||||||
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
|
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
|
||||||
{
|
{
|
||||||
RendererPointLightData data;
|
RendererPointLightData data;
|
||||||
data.Position = GetPosition(); // TODO: large-worlds
|
data.Position = position;
|
||||||
data.MinRoughness = MinRoughness;
|
data.MinRoughness = MinRoughness;
|
||||||
data.ShadowsDistance = ShadowsDistance;
|
data.ShadowsDistance = ShadowsDistance;
|
||||||
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void PostFxVolume::Collect(RenderContext& renderContext)
|
|||||||
if (_isBounded)
|
if (_isBounded)
|
||||||
{
|
{
|
||||||
Real distance;
|
Real distance;
|
||||||
if (_bounds.Contains(renderContext.View.Position, &distance) == ContainmentType::Contains)
|
if (_bounds.Contains(renderContext.View.WorldPosition, &distance) == ContainmentType::Contains)
|
||||||
{
|
{
|
||||||
if (_blendRadius > 0.0f)
|
if (_blendRadius > 0.0f)
|
||||||
weight = Math::Saturate((float)distance / _blendRadius) * weight;
|
weight = Math::Saturate((float)distance / _blendRadius) * weight;
|
||||||
|
|||||||
@@ -100,13 +100,14 @@ void SkyLight::Draw(RenderContext& renderContext)
|
|||||||
{
|
{
|
||||||
float brightness = Brightness;
|
float brightness = Brightness;
|
||||||
AdjustBrightness(renderContext.View, brightness);
|
AdjustBrightness(renderContext.View, brightness);
|
||||||
|
const Float3 position = GetPosition() - renderContext.View.Origin;
|
||||||
if ((renderContext.View.Flags & ViewFlags::SkyLights) != 0
|
if ((renderContext.View.Flags & ViewFlags::SkyLights) != 0
|
||||||
&& renderContext.View.Pass & DrawPass::GBuffer
|
&& renderContext.View.Pass & DrawPass::GBuffer
|
||||||
&& brightness > ZeroTolerance
|
&& brightness > ZeroTolerance
|
||||||
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
|
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
|
||||||
{
|
{
|
||||||
RendererSkyLightData data;
|
RendererSkyLightData data;
|
||||||
data.Position = GetPosition(); // TODO: large-worlds
|
data.Position = position;
|
||||||
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
||||||
data.VolumetricScatteringIntensity = VolumetricScatteringIntensity;
|
data.VolumetricScatteringIntensity = VolumetricScatteringIntensity;
|
||||||
data.CastVolumetricShadow = CastVolumetricShadow;
|
data.CastVolumetricShadow = CastVolumetricShadow;
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ void SplineModel::OnSplineUpdated()
|
|||||||
for (int32 j = 0; j < meshes.Count(); j++)
|
for (int32 j = 0; j < meshes.Count(); j++)
|
||||||
{
|
{
|
||||||
const auto& mesh = meshes[j];
|
const auto& mesh = meshes[j];
|
||||||
mesh.GetCorners(corners);
|
mesh.GetBox().GetCorners(corners);
|
||||||
|
|
||||||
for (int32 i = 0; i < 8; i++)
|
for (int32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ void SpotLight::Draw(RenderContext& renderContext)
|
|||||||
{
|
{
|
||||||
float brightness = ComputeBrightness();
|
float brightness = ComputeBrightness();
|
||||||
AdjustBrightness(renderContext.View, brightness);
|
AdjustBrightness(renderContext.View, brightness);
|
||||||
|
const Float3 position = GetPosition() - renderContext.View.Origin;
|
||||||
const float radius = GetScaledRadius();
|
const float radius = GetScaledRadius();
|
||||||
const float outerConeAngle = GetOuterConeAngle();
|
const float outerConeAngle = GetOuterConeAngle();
|
||||||
if ((renderContext.View.Flags & ViewFlags::SpotLights) != 0
|
if ((renderContext.View.Flags & ViewFlags::SpotLights) != 0
|
||||||
@@ -158,10 +159,10 @@ void SpotLight::Draw(RenderContext& renderContext)
|
|||||||
&& brightness > ZeroTolerance
|
&& brightness > ZeroTolerance
|
||||||
&& radius > ZeroTolerance
|
&& radius > ZeroTolerance
|
||||||
&& outerConeAngle > 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;
|
RendererSpotLightData data;
|
||||||
data.Position = GetPosition(); // TODO: large-worlds
|
data.Position = position;
|
||||||
data.MinRoughness = MinRoughness;
|
data.MinRoughness = MinRoughness;
|
||||||
data.ShadowsDistance = ShadowsDistance;
|
data.ShadowsDistance = ShadowsDistance;
|
||||||
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
data.Color = Color.ToFloat3() * (Color.A * brightness);
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
StaticModel::StaticModel(const SpawnParams& params)
|
StaticModel::StaticModel(const SpawnParams& params)
|
||||||
: ModelInstanceActor(params)
|
: ModelInstanceActor(params)
|
||||||
, _world(Matrix::Identity)
|
|
||||||
, _scaleInLightmap(1.0f)
|
, _scaleInLightmap(1.0f)
|
||||||
, _boundsScale(1.0f)
|
, _boundsScale(1.0f)
|
||||||
, _lodBias(0)
|
, _lodBias(0)
|
||||||
@@ -210,16 +209,9 @@ void StaticModel::UpdateBounds()
|
|||||||
{
|
{
|
||||||
if (Model && Model->IsLoaded())
|
if (Model && Model->IsLoaded())
|
||||||
{
|
{
|
||||||
Matrix world;
|
Transform transform = _transform;
|
||||||
if (Math::IsOne(_boundsScale))
|
transform.Scale *= _boundsScale;
|
||||||
world = _world;
|
_box = Model->GetBox(transform);
|
||||||
else
|
|
||||||
{
|
|
||||||
Transform t = _transform;
|
|
||||||
t.Scale *= _boundsScale;
|
|
||||||
t.GetWorld(world);
|
|
||||||
}
|
|
||||||
_box = Model->GetBox(world);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -240,17 +232,21 @@ void StaticModel::Draw(RenderContext& renderContext)
|
|||||||
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass);
|
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass);
|
||||||
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None)
|
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Matrix world;
|
||||||
|
renderContext.View.GetWorldMatrix(_transform, world);
|
||||||
|
|
||||||
if (renderContext.View.Pass == DrawPass::GlobalSDF)
|
if (renderContext.View.Pass == DrawPass::GlobalSDF)
|
||||||
{
|
{
|
||||||
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, _world, _box);
|
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, world, _box);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, _world);
|
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||||
|
|
||||||
// Flush vertex colors if need to
|
// Flush vertex colors if need to
|
||||||
if (_vertexColorsDirty)
|
if (_vertexColorsDirty)
|
||||||
@@ -282,18 +278,19 @@ void StaticModel::Draw(RenderContext& renderContext)
|
|||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
|
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
|
||||||
if (!Editor::IsPlayMode)
|
if (!Editor::IsPlayMode)
|
||||||
_drawState.PrevWorld = _world;
|
_drawState.PrevWorld = world;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Mesh::DrawInfo draw;
|
Mesh::DrawInfo draw;
|
||||||
draw.Buffer = &Entries;
|
draw.Buffer = &Entries;
|
||||||
draw.World = &_world;
|
draw.World = &world;
|
||||||
draw.DrawState = &_drawState;
|
draw.DrawState = &_drawState;
|
||||||
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
|
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
|
||||||
draw.LightmapUVs = &Lightmap.UVsArea;
|
draw.LightmapUVs = &Lightmap.UVsArea;
|
||||||
draw.Flags = _staticFlags;
|
draw.Flags = _staticFlags;
|
||||||
draw.DrawModes = drawModes;
|
draw.DrawModes = drawModes;
|
||||||
draw.Bounds = _sphere;
|
draw.Bounds = _sphere;
|
||||||
|
draw.Bounds.Center -= renderContext.View.Origin;
|
||||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||||
draw.LODBias = _lodBias;
|
draw.LODBias = _lodBias;
|
||||||
draw.ForcedLOD = _forcedLod;
|
draw.ForcedLOD = _forcedLod;
|
||||||
@@ -301,7 +298,7 @@ void StaticModel::Draw(RenderContext& renderContext)
|
|||||||
|
|
||||||
Model->Draw(renderContext, draw);
|
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)
|
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())
|
if (Model != nullptr && Model->IsLoaded())
|
||||||
{
|
{
|
||||||
Mesh* mesh;
|
Mesh* mesh;
|
||||||
result = Model->Intersects(ray, _world, distance, normal, &mesh);
|
result = Model->Intersects(ray, _transform, distance, normal, &mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -473,7 +470,7 @@ bool StaticModel::IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distan
|
|||||||
for (int32 i = 0; i < meshes.Count(); i++)
|
for (int32 i = 0; i < meshes.Count(); i++)
|
||||||
{
|
{
|
||||||
const auto& mesh = meshes[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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +497,7 @@ bool StaticModel::IntersectsEntry(const Ray& ray, Real& distance, Vector3& norma
|
|||||||
const auto& mesh = meshes[i];
|
const auto& mesh = meshes[i];
|
||||||
Real dst;
|
Real dst;
|
||||||
Vector3 nrm;
|
Vector3 nrm;
|
||||||
if (mesh.Intersects(ray, _world, dst, nrm) && dst < closest)
|
if (mesh.Intersects(ray, _transform, dst, nrm) && dst < closest)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
closest = dst;
|
closest = dst;
|
||||||
@@ -520,7 +517,6 @@ void StaticModel::OnTransformChanged()
|
|||||||
// Base
|
// Base
|
||||||
ModelInstanceActor::OnTransformChanged();
|
ModelInstanceActor::OnTransformChanged();
|
||||||
|
|
||||||
_transform.GetWorld(_world);
|
|
||||||
UpdateBounds();
|
UpdateBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ API_CLASS() class FLAXENGINE_API StaticModel : public ModelInstanceActor
|
|||||||
{
|
{
|
||||||
DECLARE_SCENE_OBJECT(StaticModel);
|
DECLARE_SCENE_OBJECT(StaticModel);
|
||||||
private:
|
private:
|
||||||
Matrix _world;
|
|
||||||
GeometryDrawStateData _drawState;
|
GeometryDrawStateData _drawState;
|
||||||
float _scaleInLightmap;
|
float _scaleInLightmap;
|
||||||
float _boundsScale;
|
float _boundsScale;
|
||||||
@@ -50,15 +49,6 @@ public:
|
|||||||
LightmapEntry Lightmap;
|
LightmapEntry Lightmap;
|
||||||
|
|
||||||
public:
|
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>
|
/// <summary>
|
||||||
/// Gets the model scale in lightmap (applied to all the meshes).
|
/// Gets the model scale in lightmap (applied to all the meshes).
|
||||||
/// </summary>
|
/// </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 "Level.h"
|
||||||
#include "ActorsCache.h"
|
#include "ActorsCache.h"
|
||||||
|
#include "LargeWorlds.h"
|
||||||
#include "SceneQuery.h"
|
#include "SceneQuery.h"
|
||||||
#include "SceneObjectsFactory.h"
|
#include "SceneObjectsFactory.h"
|
||||||
#include "Scene/Scene.h"
|
#include "Scene/Scene.h"
|
||||||
@@ -39,6 +40,19 @@
|
|||||||
#include "Engine/Serialization/JsonSerializer.h"
|
#include "Engine/Serialization/JsonSerializer.h"
|
||||||
#endif
|
#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
|
bool LayersMask::HasLayer(const StringView& layerName) const
|
||||||
{
|
{
|
||||||
return HasLayer(Level::GetLayerIndex(layerName));
|
return HasLayer(Level::GetLayerIndex(layerName));
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ void SceneRendering::Draw(RenderContext& renderContext)
|
|||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
auto& view = renderContext.View;
|
auto& view = renderContext.View;
|
||||||
const BoundingFrustum frustum = view.CullingFrustum;
|
const BoundingFrustum frustum = view.CullingFrustum;
|
||||||
|
const Vector3 origin = view.Origin;
|
||||||
renderContext.List->Scenes.Add(this);
|
renderContext.List->Scenes.Add(this);
|
||||||
|
|
||||||
// Draw all visual components
|
// Draw all visual components
|
||||||
@@ -40,7 +41,8 @@ void SceneRendering::Draw(RenderContext& renderContext)
|
|||||||
{
|
{
|
||||||
for (int32 i = 0; i < Actors.Count(); i++)
|
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 (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)) && e.Actor->GetStaticFlags() & view.StaticFlagsMask)
|
||||||
{
|
{
|
||||||
#if SCENE_RENDERING_USE_PROFILER
|
#if SCENE_RENDERING_USE_PROFILER
|
||||||
@@ -54,7 +56,8 @@ void SceneRendering::Draw(RenderContext& renderContext)
|
|||||||
{
|
{
|
||||||
for (int32 i = 0; i < Actors.Count(); i++)
|
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 (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)))
|
||||||
{
|
{
|
||||||
#if SCENE_RENDERING_USE_PROFILER
|
#if SCENE_RENDERING_USE_PROFILER
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ void BoxCollider::UpdateBounds()
|
|||||||
{
|
{
|
||||||
// Cache bounds
|
// Cache bounds
|
||||||
OrientedBoundingBox::CreateCentered(_center, _size, _bounds);
|
OrientedBoundingBox::CreateCentered(_center, _size, _bounds);
|
||||||
_bounds.Transform(_transform.GetWorld());
|
_bounds.Transform(_transform);
|
||||||
_bounds.GetBoundingBox(_box);
|
_bounds.GetBoundingBox(_box);
|
||||||
BoundingSphere::FromBox(_box, _sphere);
|
BoundingSphere::FromBox(_box, _sphere);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void CapsuleCollider::UpdateBounds()
|
|||||||
// Cache bounds
|
// Cache bounds
|
||||||
const float radiusTwice = _radius * 2.0f;
|
const float radiusTwice = _radius * 2.0f;
|
||||||
OrientedBoundingBox::CreateCentered(_center, Vector3(_height + radiusTwice, radiusTwice, radiusTwice), _orientedBox);
|
OrientedBoundingBox::CreateCentered(_center, Vector3(_height + radiusTwice, radiusTwice, radiusTwice), _orientedBox);
|
||||||
_orientedBox.Transform(_transform.GetWorld());
|
_orientedBox.Transform(_transform);
|
||||||
_orientedBox.GetBoundingBox(_box);
|
_orientedBox.GetBoundingBox(_box);
|
||||||
BoundingSphere::FromBox(_box, _sphere);
|
BoundingSphere::FromBox(_box, _sphere);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include "Engine/Core/Math/Math.h"
|
#include "Engine/Core/Math/Math.h"
|
||||||
#include "Engine/Level/Actors/BoxBrush.h"
|
#include "Engine/Level/Actors/BoxBrush.h"
|
||||||
#include "Engine/Level/Actors/StaticModel.h"
|
#include "Engine/Level/Actors/StaticModel.h"
|
||||||
#include "Engine/ContentImporters/ImportTexture.h"
|
|
||||||
#include "Engine/Level/Scene/Scene.h"
|
#include "Engine/Level/Scene/Scene.h"
|
||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
#include "Engine/Terrain/Terrain.h"
|
#include "Engine/Terrain/Terrain.h"
|
||||||
@@ -40,10 +39,6 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC
|
|||||||
entry.AsStaticModel.Actor = staticModel;
|
entry.AsStaticModel.Actor = staticModel;
|
||||||
entry.Scale = Math::Clamp(staticModel->GetScaleInLightmap(), 0.0f, LIGHTMAP_SCALE_MAX);
|
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
|
// Use the first LOD
|
||||||
const int32 lodIndex = 0;
|
const int32 lodIndex = 0;
|
||||||
auto& lod = model->LODs[lodIndex];
|
auto& lod = model->LODs[lodIndex];
|
||||||
@@ -61,18 +56,16 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(Warning, "Model \'{0}\' mesh index {1} (lod: {2}) has missing lightmap UVs (at actor: {3})",
|
LOG(Warning, "Model \'{0}\' mesh index {1} (lod: {2}) has missing lightmap UVs (at actor: {3})", model->GetPath(), meshIndex, lodIndex, staticModel->GetNamePath());
|
||||||
model->GetPath(),
|
|
||||||
meshIndex,
|
|
||||||
lodIndex,
|
|
||||||
staticModel->GetNamePath());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useLightmap && anyValid && entry.Scale > ZeroTolerance)
|
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);
|
results.Add(entry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
|
|||||||
auto& lod = staticModel->Model->LODs[0];
|
auto& lod = staticModel->Model->LODs[0];
|
||||||
|
|
||||||
Matrix worldMatrix;
|
Matrix worldMatrix;
|
||||||
staticModel->GetWorld(&worldMatrix);
|
staticModel->GetTransform().GetWorld(worldMatrix);
|
||||||
Matrix::Transpose(worldMatrix, shaderData.WorldMatrix);
|
Matrix::Transpose(worldMatrix, shaderData.WorldMatrix);
|
||||||
shaderData.LightmapArea = staticModel->Lightmap.UVsArea;
|
shaderData.LightmapArea = staticModel->Lightmap.UVsArea;
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ void TerrainChunk::UpdateBounds()
|
|||||||
{
|
{
|
||||||
const Vector3 boundsExtent = _patch->_terrain->_boundsExtent;
|
const Vector3 boundsExtent = _patch->_terrain->_boundsExtent;
|
||||||
const float size = (float)_patch->_terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX;
|
const float size = (float)_patch->_terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX;
|
||||||
Transform terrainTransform = _patch->_terrain->_transform;
|
const Transform terrainTransform = _patch->_terrain->_transform;
|
||||||
|
|
||||||
Transform localTransform;
|
Transform localTransform;
|
||||||
localTransform.Translation = _patch->_offset + Vector3(_x * size, _yOffset, _z * size);
|
localTransform.Translation = _patch->_offset + Vector3(_x * size, _yOffset, _z * size);
|
||||||
@@ -197,11 +197,8 @@ void TerrainChunk::UpdateBounds()
|
|||||||
localTransform.Scale = Vector3(size, _yHeight, size);
|
localTransform.Scale = Vector3(size, _yHeight, size);
|
||||||
localTransform = terrainTransform.LocalToWorld(localTransform);
|
localTransform = terrainTransform.LocalToWorld(localTransform);
|
||||||
|
|
||||||
Matrix world;
|
|
||||||
localTransform.GetWorld(world);
|
|
||||||
|
|
||||||
OrientedBoundingBox obb(Vector3::Zero, Vector3::One);
|
OrientedBoundingBox obb(Vector3::Zero, Vector3::One);
|
||||||
obb.Transform(world);
|
obb.Transform(localTransform);
|
||||||
obb.GetBoundingBox(_bounds);
|
obb.GetBoundingBox(_bounds);
|
||||||
_boundsCenter = _bounds.GetCenter();
|
_boundsCenter = _bounds.GetCenter();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user