More work for large worlds
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user