More work for large worlds

This commit is contained in:
Wojtek Figat
2022-06-30 22:06:35 +02:00
parent 4007c5e29c
commit b40a890d31
10 changed files with 103 additions and 27 deletions

View File

@@ -157,6 +157,11 @@ bool SkinnedModel::Intersects(const Ray& ray, const Matrix& world, Real& distanc
return LODs[lodIndex].Intersects(ray, world, distance, normal, mesh);
}
bool SkinnedModel::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, SkinnedMesh** mesh, int32 lodIndex)
{
return LODs[lodIndex].Intersects(ray, transform, distance, normal, mesh);
}
BoundingBox SkinnedModel::GetBox(const Matrix& world, int32 lodIndex) const
{
return LODs[lodIndex].GetBox(world);

View File

@@ -177,6 +177,18 @@ public:
/// <returns>True whether the two objects intersected</returns>
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, SkinnedMesh** mesh, int32 lodIndex = 0);
/// <summary>
/// Determines if there is an intersection between the SkinnedModel and a Ray in given world using given instance.
/// </summary>
/// <param name="ray">The ray to test</param>
/// <param name="transform">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, SkinnedMesh** mesh, int32 lodIndex = 0);
/// <summary>
/// Gets the model bounding box in custom matrix world space (rig pose transformed by matrix, not animated).
/// </summary>

View File

@@ -127,6 +127,20 @@ bool SkinnedMesh::Intersects(const Ray& ray, const Matrix& world, Real& distance
return transformedBox.Intersects(ray, distance, normal);
}
bool SkinnedMesh::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const
{
// Transform points
Vector3 min, max;
transform.LocalToWorld(_box.Minimum, min);
transform.LocalToWorld(_box.Maximum, max);
// Get transformed box
BoundingBox transformedBox(min, max);
// Test ray on a box
return transformedBox.Intersects(ray, distance, normal);
}
void SkinnedMesh::Render(GPUContext* context) const
{
ASSERT(IsInitialized());

View File

@@ -150,6 +150,16 @@ public:
/// <returns>True whether the two objects intersected</returns>
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const;
/// <summary>
/// Determines if there is an intersection between the mesh and a ray in given world
/// </summary>
/// <param name="ray">The ray to test</param>
/// <param name="transform">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;
/// <summary>
/// Retrieves the eight corners of the bounding box.
/// </summary>

View File

@@ -100,6 +100,31 @@ bool SkinnedModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& dist
return result;
}
bool SkinnedModelLOD::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, SkinnedMesh** mesh)
{
// Check all meshes
bool result = false;
Real closest = MAX_float;
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, transform, dst, nrm) && dst < closest)
{
result = true;
*mesh = &Meshes[i];
closest = dst;
closestNormal = nrm;
}
}
distance = closest;
normal = closestNormal;
return result;
}
BoundingBox SkinnedModelLOD::GetBox(const Matrix& world) const
{
// Find minimum and maximum points of all the meshes

View File

@@ -63,6 +63,17 @@ public:
/// <returns>True whether the two objects intersected</returns>
bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, SkinnedMesh** mesh);
/// <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">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, SkinnedMesh** mesh);
/// <summary>
/// Get model bounding box in transformed world for given instance buffer
/// </summary>

View File

@@ -23,7 +23,6 @@ AnimatedModel::AnimatedModel(const SpawnParams& params)
, _lastUpdateFrame(0)
{
GraphInstance.Object = this;
_world = Matrix::Identity;
UpdateBounds();
SkinnedModel.Changed.Bind<AnimatedModel, &AnimatedModel::OnSkinnedModelChanged>(this);
@@ -122,7 +121,8 @@ void AnimatedModel::GetCurrentPose(Array<Matrix>& nodesTransformation, bool worl
nodesTransformation = GraphInstance.NodesPose;
if (worldSpace)
{
const auto world = _world;
Matrix world;
_transform.GetWorld(world);
for (auto& m : nodesTransformation)
m = m * world;
}
@@ -136,8 +136,10 @@ void AnimatedModel::SetCurrentPose(const Array<Matrix>& nodesTransformation, boo
GraphInstance.NodesPose = nodesTransformation;
if (worldSpace)
{
Matrix world;
_transform.GetWorld(world);
Matrix invWorld;
Matrix::Invert(_world, invWorld);
Matrix::Invert(world, invWorld);
for (auto& m : GraphInstance.NodesPose)
m = invWorld * m;
}
@@ -153,7 +155,11 @@ void AnimatedModel::GetNodeTransformation(int32 nodeIndex, Matrix& nodeTransform
else
nodeTransformation = Matrix::Identity;
if (worldSpace)
nodeTransformation = nodeTransformation * _world;
{
Matrix world;
_transform.GetWorld(world);
nodeTransformation = nodeTransformation * world;
}
}
void AnimatedModel::GetNodeTransformation(const StringView& nodeName, Matrix& nodeTransformation, bool worldSpace) const
@@ -545,7 +551,7 @@ void AnimatedModel::UpdateBounds()
{
UpdateLocalBounds();
BoundingBox::Transform(_boxLocal, _world, _box);
BoundingBox::Transform(_boxLocal, _transform, _box);
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
@@ -696,7 +702,9 @@ void AnimatedModel::Draw(RenderContext& renderContext)
return; // TODO: Animated Model rendering to Global SDF
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
return; // No supported
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, _world);
Matrix world;
renderContext.View.GetWorldMatrix(_transform, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass & (int32)renderContext.View.GetShadowsDrawPassMask(ShadowsMode));
if (SkinnedModel && SkinnedModel->IsLoaded() && drawModes != DrawPass::None)
@@ -708,7 +716,7 @@ void AnimatedModel::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
_skinningData.Flush(GPUDevice::Instance->GetMainContext());
@@ -717,7 +725,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
draw.Buffer = &Entries;
draw.Skinning = &_skinningData;
draw.BlendShapes = &_blendShapes;
draw.World = &_world;
draw.World = &world;
draw.DrawState = &_drawState;
draw.DrawModes = drawModes;
draw.Bounds = _sphere;
@@ -729,7 +737,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
}
}
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, _world);
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
}
#if USE_EDITOR
@@ -760,7 +768,7 @@ bool AnimatedModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& no
if (SkinnedModel != nullptr && SkinnedModel->IsLoaded())
{
SkinnedMesh* mesh;
result |= SkinnedModel->Intersects(ray, _world, distance, normal, &mesh);
result |= SkinnedModel->Intersects(ray, _transform, distance, normal, &mesh);
}
return result;
@@ -833,7 +841,7 @@ bool AnimatedModel::IntersectsEntry(int32 entryIndex, const Ray& ray, Real& dist
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;
}
@@ -860,7 +868,7 @@ bool AnimatedModel::IntersectsEntry(const Ray& ray, Real& distance, Vector3& nor
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;
@@ -880,8 +888,7 @@ void AnimatedModel::OnTransformChanged()
// Base
ModelInstanceActor::OnTransformChanged();
_transform.GetWorld(_world);
BoundingBox::Transform(_boxLocal, _world, _box);
BoundingBox::Transform(_boxLocal, _transform, _box);
BoundingSphere::FromBox(_box, _sphere);
if (_sceneRenderingKey != -1)
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);

View File

@@ -55,7 +55,6 @@ public:
private:
BoundingBox _boxLocal;
Matrix _world;
GeometryDrawStateData _drawState;
SkinnedMeshDrawData _skinningData;
AnimationUpdateMode _actualMode;
@@ -156,14 +155,6 @@ public:
/// </summary>
AnimGraphInstanceData GraphInstance;
/// <summary>
/// Gets the model world matrix transform.
/// </summary>
FORCE_INLINE void GetWorld(Matrix* world) const
{
*world = _world;
}
/// <summary>
/// Resets the animation state (clears the instance state data but preserves the instance parameters values).
/// </summary>

View File

@@ -372,13 +372,14 @@ void SplineModel::Draw(RenderContext& renderContext)
drawCall.PerInstanceRandom = GetPerInstanceRandom();
_preTransform.GetWorld(drawCall.Deformable.LocalMatrix);
const Transform splineTransform = GetTransform();
splineTransform.GetWorld(drawCall.World);
renderContext.View.GetWorldMatrix(splineTransform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation() + drawCall.Deformable.LocalMatrix.GetTranslation();
const float worldDeterminantSign = drawCall.World.RotDeterminant() * drawCall.Deformable.LocalMatrix.RotDeterminant();
for (int32 segment = 0; segment < _instances.Count(); segment++)
{
auto& instance = _instances[segment];
if (!(renderContext.View.IsCullingDisabled || renderContext.View.CullingFrustum.Intersects(instance.Sphere)))
BoundingSphere instanceSphere(instance.Sphere.Center - renderContext.View.Origin, instance.Sphere.Radius);
if (!(renderContext.View.IsCullingDisabled || renderContext.View.CullingFrustum.Intersects(instanceSphere)))
continue;
drawCall.Deformable.Segment = (float)segment;
@@ -390,7 +391,7 @@ void SplineModel::Draw(RenderContext& renderContext)
}
else
{
lodIndex = RenderTools::ComputeModelLOD(model, instance.Sphere.Center, (float)instance.Sphere.Radius, renderContext);
lodIndex = RenderTools::ComputeModelLOD(model, instanceSphere.Center, (float)instanceSphere.Radius, renderContext);
if (lodIndex == -1)
continue;
}

View File

@@ -19,7 +19,7 @@ API_CLASS(Static) class FLAXENGINE_API LargeWorlds
/// <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;
API_FIELD() static constexpr Real ChunkSize = 262144;
/// <summary>
/// Updates the large world origin to match the input position. The origin is snapped to the best matching chunk location.