Add distance-based and frustum-based culling to cloth
This commit is contained in:
@@ -881,7 +881,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
|
|||||||
Matrix::Transformation(_transform.Scale, _transform.Orientation, translation, world);
|
Matrix::Transformation(_transform.Scale, _transform.Orientation, translation, world);
|
||||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||||
|
|
||||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.Position + renderContext.View.Origin));
|
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
|
||||||
if (_skinningData.IsReady())
|
if (_skinningData.IsReady())
|
||||||
{
|
{
|
||||||
// Flush skinning data with GPU
|
// Flush skinning data with GPU
|
||||||
@@ -924,7 +924,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
|
|||||||
Matrix::Transformation(_transform.Scale, _transform.Orientation, translation, world);
|
Matrix::Transformation(_transform.Scale, _transform.Orientation, translation, world);
|
||||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||||
|
|
||||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.Position + renderContext.View.Origin));
|
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
|
||||||
if (_skinningData.IsReady())
|
if (_skinningData.IsReady())
|
||||||
{
|
{
|
||||||
// Flush skinning data with GPU
|
// Flush skinning data with GPU
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Cloth.h"
|
#include "Cloth.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Core/Math/Ray.h"
|
#include "Engine/Core/Math/Ray.h"
|
||||||
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
#include "Engine/Graphics/RenderTools.h"
|
#include "Engine/Graphics/RenderTools.h"
|
||||||
#include "Engine/Graphics/Models/MeshBase.h"
|
#include "Engine/Graphics/Models/MeshBase.h"
|
||||||
#include "Engine/Graphics/Models/MeshDeformation.h"
|
#include "Engine/Graphics/Models/MeshDeformation.h"
|
||||||
@@ -21,6 +22,9 @@ Cloth::Cloth(const SpawnParams& params)
|
|||||||
{
|
{
|
||||||
// Use the first mesh by default
|
// Use the first mesh by default
|
||||||
_mesh.LODIndex = _mesh.MeshIndex = 0;
|
_mesh.LODIndex = _mesh.MeshIndex = 0;
|
||||||
|
|
||||||
|
// Register for drawing to handle culling and distance LOD
|
||||||
|
_drawCategory = SceneRendering::SceneDrawAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelInstanceActor::MeshReference Cloth::GetMesh() const
|
ModelInstanceActor::MeshReference Cloth::GetMesh() const
|
||||||
@@ -441,6 +445,7 @@ void Cloth::EndPlay()
|
|||||||
void Cloth::OnEnable()
|
void Cloth::OnEnable()
|
||||||
{
|
{
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
|
||||||
GetSceneRendering()->AddPhysicsDebug<Cloth, &Cloth::DrawPhysicsDebug>(this);
|
GetSceneRendering()->AddPhysicsDebug<Cloth, &Cloth::DrawPhysicsDebug>(this);
|
||||||
#endif
|
#endif
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
@@ -461,6 +466,7 @@ void Cloth::OnDisable()
|
|||||||
#endif
|
#endif
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
GetSceneRendering()->RemovePhysicsDebug<Cloth, &Cloth::DrawPhysicsDebug>(this);
|
GetSceneRendering()->RemovePhysicsDebug<Cloth, &Cloth::DrawPhysicsDebug>(this);
|
||||||
|
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,6 +586,8 @@ bool Cloth::CreateCloth()
|
|||||||
deformation->AddDeformer(mesh.LODIndex, mesh.MeshIndex, MeshBufferType::Vertex1, deformer);
|
deformation->AddDeformer(mesh.LODIndex, mesh.MeshIndex, MeshBufferType::Vertex1, deformer);
|
||||||
_meshDeformation = deformation;
|
_meshDeformation = deformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastMinDstSqr = MAX_Real;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -588,6 +596,7 @@ bool Cloth::CreateCloth()
|
|||||||
void Cloth::DestroyCloth()
|
void Cloth::DestroyCloth()
|
||||||
{
|
{
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
|
_lastMinDstSqr = MAX_Real;
|
||||||
if (_meshDeformation)
|
if (_meshDeformation)
|
||||||
{
|
{
|
||||||
Function<void(const MeshBase*, MeshDeformationData&)> deformer;
|
Function<void(const MeshBase*, MeshDeformationData&)> deformer;
|
||||||
@@ -722,20 +731,38 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cloth::OnPreUpdate()
|
bool Cloth::OnPreUpdate()
|
||||||
{
|
{
|
||||||
|
if (!IsActiveInHierarchy())
|
||||||
|
return true;
|
||||||
|
if (!_simulationSettings.UpdateWhenOffscreen && _simulationSettings.CullDistance > 0)
|
||||||
|
{
|
||||||
|
// Cull based on distance
|
||||||
|
bool cull = false;
|
||||||
|
if (_lastMinDstSqr >= Math::Square(_simulationSettings.CullDistance))
|
||||||
|
cull = true; // Cull
|
||||||
|
else if (_lastMinDstSqr >= Math::Square(_simulationSettings.CullDistance * 0.8f))
|
||||||
|
cull = _frameCounter % 4 == 0; // Update once every 4 frames
|
||||||
|
else if (_lastMinDstSqr >= Math::Square(_simulationSettings.CullDistance * 0.5f))
|
||||||
|
cull = _frameCounter % 2 == 0; // Update once every 2 frames
|
||||||
|
_lastMinDstSqr = MAX_Real;
|
||||||
|
_frameCounter++;
|
||||||
|
if (cull)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Get current skinned mesh pose for the simulation of the non-kinematic vertices
|
// Get current skinned mesh pose for the simulation of the non-kinematic vertices
|
||||||
if (auto* animatedModel = Cast<AnimatedModel>(GetParent()))
|
if (auto* animatedModel = Cast<AnimatedModel>(GetParent()))
|
||||||
{
|
{
|
||||||
if (animatedModel->GraphInstance.NodesPose.IsEmpty() || _paint.IsEmpty())
|
if (animatedModel->GraphInstance.NodesPose.IsEmpty() || _paint.IsEmpty())
|
||||||
return;
|
return false;
|
||||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||||
if (mesh.Actor == nullptr)
|
if (mesh.Actor == nullptr)
|
||||||
return;
|
return false;
|
||||||
BytesContainer verticesData;
|
BytesContainer verticesData;
|
||||||
int32 verticesCount;
|
int32 verticesCount;
|
||||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Vertex0, verticesData, verticesCount))
|
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Vertex0, verticesData, verticesCount))
|
||||||
return;
|
return false;
|
||||||
PROFILE_CPU_NAMED("Skinned Pose");
|
PROFILE_CPU_NAMED("Skinned Pose");
|
||||||
auto vbStride = (uint32)verticesData.Length() / verticesCount;
|
auto vbStride = (uint32)verticesData.Length() / verticesCount;
|
||||||
ASSERT(vbStride == sizeof(VB0SkinnedElementType));
|
ASSERT(vbStride == sizeof(VB0SkinnedElementType));
|
||||||
@@ -749,6 +776,7 @@ void Cloth::OnPreUpdate()
|
|||||||
Array<Matrix> pose;
|
Array<Matrix> pose;
|
||||||
animatedModel->GetCurrentPose(pose);
|
animatedModel->GetCurrentPose(pose);
|
||||||
const SkeletonData& skeleton = animatedModel->SkinnedModel->Skeleton;
|
const SkeletonData& skeleton = animatedModel->SkinnedModel->Skeleton;
|
||||||
|
const SkeletonBone* bones = skeleton.Bones.Get();
|
||||||
|
|
||||||
// Animated model uses skinning thus requires to set vertex position inverse to skeleton bones
|
// Animated model uses skinning thus requires to set vertex position inverse to skeleton bones
|
||||||
const float* paint = _paint.Get();
|
const float* paint = _paint.Get();
|
||||||
@@ -763,24 +791,24 @@ void Cloth::OnPreUpdate()
|
|||||||
const Float4 blendWeights = vb0.BlendWeights.ToFloat4();
|
const Float4 blendWeights = vb0.BlendWeights.ToFloat4();
|
||||||
// TODO: optimize this or use _skinningData from AnimatedModel to access current mesh bones data directly
|
// TODO: optimize this or use _skinningData from AnimatedModel to access current mesh bones data directly
|
||||||
Matrix matrix;
|
Matrix matrix;
|
||||||
const SkeletonBone& bone0 = skeleton.Bones[vb0.BlendIndices.R];
|
const SkeletonBone& bone0 = bones[vb0.BlendIndices.R];
|
||||||
Matrix::Multiply(bone0.OffsetMatrix, pose[bone0.NodeIndex], matrix);
|
Matrix::Multiply(bone0.OffsetMatrix, pose[bone0.NodeIndex], matrix);
|
||||||
Matrix boneMatrix = matrix * blendWeights.X;
|
Matrix boneMatrix = matrix * blendWeights.X;
|
||||||
if (blendWeights.Y > 0.0f)
|
if (blendWeights.Y > 0.0f)
|
||||||
{
|
{
|
||||||
const SkeletonBone& bone1 = skeleton.Bones[vb0.BlendIndices.G];
|
const SkeletonBone& bone1 = bones[vb0.BlendIndices.G];
|
||||||
Matrix::Multiply(bone1.OffsetMatrix, pose[bone1.NodeIndex], matrix);
|
Matrix::Multiply(bone1.OffsetMatrix, pose[bone1.NodeIndex], matrix);
|
||||||
boneMatrix += matrix * blendWeights.Y;
|
boneMatrix += matrix * blendWeights.Y;
|
||||||
}
|
}
|
||||||
if (blendWeights.Z > 0.0f)
|
if (blendWeights.Z > 0.0f)
|
||||||
{
|
{
|
||||||
const SkeletonBone& bone2 = skeleton.Bones[vb0.BlendIndices.B];
|
const SkeletonBone& bone2 = bones[vb0.BlendIndices.B];
|
||||||
Matrix::Multiply(bone2.OffsetMatrix, pose[bone2.NodeIndex], matrix);
|
Matrix::Multiply(bone2.OffsetMatrix, pose[bone2.NodeIndex], matrix);
|
||||||
boneMatrix += matrix * blendWeights.Z;
|
boneMatrix += matrix * blendWeights.Z;
|
||||||
}
|
}
|
||||||
if (blendWeights.W > 0.0f)
|
if (blendWeights.W > 0.0f)
|
||||||
{
|
{
|
||||||
const SkeletonBone& bone3 = skeleton.Bones[vb0.BlendIndices.A];
|
const SkeletonBone& bone3 = bones[vb0.BlendIndices.A];
|
||||||
Matrix::Multiply(bone3.OffsetMatrix, pose[bone3.NodeIndex], matrix);
|
Matrix::Multiply(bone3.OffsetMatrix, pose[bone3.NodeIndex], matrix);
|
||||||
boneMatrix += matrix * blendWeights.W;
|
boneMatrix += matrix * blendWeights.W;
|
||||||
}
|
}
|
||||||
@@ -806,6 +834,8 @@ void Cloth::OnPreUpdate()
|
|||||||
|
|
||||||
PhysicsBackend::UnlockClothParticles(_cloth);
|
PhysicsBackend::UnlockClothParticles(_cloth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cloth::OnPostUpdate()
|
void Cloth::OnPostUpdate()
|
||||||
@@ -823,11 +853,28 @@ void Cloth::OnPostUpdate()
|
|||||||
// Update bounds (for mesh culling)
|
// Update bounds (for mesh culling)
|
||||||
auto* actor = (ModelInstanceActor*)GetParent();
|
auto* actor = (ModelInstanceActor*)GetParent();
|
||||||
actor->UpdateBounds();
|
actor->UpdateBounds();
|
||||||
|
if (_sceneRenderingKey != -1)
|
||||||
|
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cloth::Draw(RenderContext& renderContext)
|
||||||
|
{
|
||||||
|
// Update min draw distance for the next simulation tick
|
||||||
|
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cloth::Draw(RenderContextBatch& renderContextBatch)
|
||||||
|
{
|
||||||
|
// Update min draw distance for the next simulation tick
|
||||||
|
const RenderContext& renderContext = renderContextBatch.GetMainContext();
|
||||||
|
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
|
||||||
|
}
|
||||||
|
|
||||||
void Cloth::RunClothDeformer(const MeshBase* mesh, MeshDeformationData& deformation)
|
void Cloth::RunClothDeformer(const MeshBase* mesh, MeshDeformationData& deformation)
|
||||||
{
|
{
|
||||||
|
if (!IsActiveInHierarchy())
|
||||||
|
return;
|
||||||
if (!_simulationSettings.ComputeNormals && deformation.Type != MeshBufferType::Vertex0)
|
if (!_simulationSettings.ComputeNormals && deformation.Type != MeshBufferType::Vertex0)
|
||||||
return;
|
return;
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Cloth\"), ActorToolbox(\"Physics\")") class FLAXENGINE_API Cloth : public Actor
|
API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Cloth\"), ActorToolbox(\"Physics\")") class FLAXENGINE_API Cloth : public Actor
|
||||||
{
|
{
|
||||||
|
friend class PhysicsBackend;
|
||||||
DECLARE_SCENE_OBJECT(Cloth);
|
DECLARE_SCENE_OBJECT(Cloth);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -129,12 +130,22 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Cloth\"), ActorToolbox(\"Ph
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target cloth solver iterations per second. The executed number of iterations per second may vary dependent on many performance factors. However, at least one iteration per frame is solved regardless of the value set.
|
/// Target cloth solver iterations per second. The executed number of iterations per second may vary dependent on many performance factors. However, at least one iteration per frame is solved regardless of the value set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float SolverFrequency = 300.0f;
|
API_FIELD() float SolverFrequency = 200.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum distance from the camera at which to run cloth simulation. Used to improve performance and skip updating too far clothes. The physics system might reduce the update rate for clothes far enough (eg. half this distance). 0 to disable any culling.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() float CullDistance = 5000.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the cloth will be updated even when an actor cannot be seen by any camera. Otherwise, the cloth simulation will stop running when the actor is off-screen.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() bool UpdateWhenOffscreen = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum distance cloth particles can move from the original location (within local-space of the actor). Scaled by painted per-particle value (0-1) to restrict movement of certain particles.
|
/// The maximum distance cloth particles can move from the original location (within local-space of the actor). Scaled by painted per-particle value (0-1) to restrict movement of certain particles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float MaxDistance = 1000.0f;
|
API_FIELD() float MaxParticleDistance = 1000.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables automatic normal vectors computing for the cloth mesh, otherwise original mesh normals will be used.
|
/// Enables automatic normal vectors computing for the cloth mesh, otherwise original mesh normals will be used.
|
||||||
@@ -207,6 +218,9 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Cloth\"), ActorToolbox(\"Ph
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void* _cloth = nullptr;
|
void* _cloth = nullptr;
|
||||||
|
Real _lastMinDstSqr = MAX_Real;
|
||||||
|
uint32 _frameCounter = 0;
|
||||||
|
int32 _sceneRenderingKey = -1;
|
||||||
ForceSettings _forceSettings;
|
ForceSettings _forceSettings;
|
||||||
CollisionSettings _collisionSettings;
|
CollisionSettings _collisionSettings;
|
||||||
SimulationSettings _simulationSettings;
|
SimulationSettings _simulationSettings;
|
||||||
@@ -220,7 +234,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mesh to use for the cloth simulation (single mesh from specific LOD).
|
/// Gets the mesh to use for the cloth simulation (single mesh from specific LOD).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks></remarks>
|
|
||||||
API_PROPERTY(Attributes="EditorOrder(0), EditorDisplay(\"Cloth\")")
|
API_PROPERTY(Attributes="EditorOrder(0), EditorDisplay(\"Cloth\")")
|
||||||
ModelInstanceActor::MeshReference GetMesh() const;
|
ModelInstanceActor::MeshReference GetMesh() const;
|
||||||
|
|
||||||
@@ -316,11 +329,13 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_FUNCTION() void SetPaint(Span<const float> value);
|
API_FUNCTION() void SetPaint(Span<const float> value);
|
||||||
|
|
||||||
void OnPreUpdate();
|
bool OnPreUpdate();
|
||||||
void OnPostUpdate();
|
void OnPostUpdate();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// [Actor]
|
// [Actor]
|
||||||
|
void Draw(RenderContext& renderContext) override;
|
||||||
|
void Draw(RenderContextBatch& renderContextBatch) override;
|
||||||
bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override;
|
bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override;
|
||||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
#include "Engine/Physics/Actors/Cloth.h"
|
#include "Engine/Physics/Actors/Cloth.h"
|
||||||
#include "Engine/Threading/JobSystem.h"
|
#include "Engine/Threading/JobSystem.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
#include <ThirdParty/NvCloth/Callbacks.h>
|
#include <ThirdParty/NvCloth/Callbacks.h>
|
||||||
#include <ThirdParty/NvCloth/Factory.h>
|
#include <ThirdParty/NvCloth/Factory.h>
|
||||||
#include <ThirdParty/NvCloth/Cloth.h>
|
#include <ThirdParty/NvCloth/Cloth.h>
|
||||||
@@ -94,15 +95,12 @@ struct ScenePhysX
|
|||||||
#endif
|
#endif
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
nv::cloth::Solver* ClothSolver = nullptr;
|
nv::cloth::Solver* ClothSolver = nullptr;
|
||||||
|
Array<nv::cloth::Cloth*> ClothsList;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
void PreSimulateCloth(int32 i);
|
void PreSimulateCloth(int32 i);
|
||||||
void SimulateCloth(int32 i)
|
void SimulateCloth(int32 i);
|
||||||
{
|
|
||||||
PROFILE_CPU();
|
|
||||||
ClothSolver->simulateChunk(i);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -171,12 +169,8 @@ struct FabricSettings
|
|||||||
Desc.InvMassesStride == r.InvMassesStride)
|
Desc.InvMassesStride == r.InvMassesStride)
|
||||||
{
|
{
|
||||||
if (Desc.InvMassesData && r.InvMassesData)
|
if (Desc.InvMassesData && r.InvMassesData)
|
||||||
{
|
return Platform::MemoryCompare(InvMasses.Get(), r.InvMassesData, r.VerticesCount * r.InvMassesStride) == 0;
|
||||||
bool matches = Platform::MemoryCompare(InvMasses.Get(), r.InvMassesData, r.VerticesCount * r.InvMassesStride) == 0;
|
return !Desc.InvMassesData && !r.InvMassesData;
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
bool matches = !Desc.InvMassesData && !r.InvMassesData;
|
|
||||||
return matches;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -184,9 +178,10 @@ struct FabricSettings
|
|||||||
|
|
||||||
struct ClothSettings
|
struct ClothSettings
|
||||||
{
|
{
|
||||||
|
bool Culled = false;
|
||||||
bool SceneCollisions = false;
|
bool SceneCollisions = false;
|
||||||
byte CollisionsUpdateFramesLeft = 0;
|
|
||||||
bool CollisionsUpdateFramesRandomize = true;
|
bool CollisionsUpdateFramesRandomize = true;
|
||||||
|
byte CollisionsUpdateFramesLeft = 0;
|
||||||
float GravityScale = 1.0f;
|
float GravityScale = 1.0f;
|
||||||
float CollisionThickness = 0.0f;
|
float CollisionThickness = 0.0f;
|
||||||
Cloth* Actor;
|
Cloth* Actor;
|
||||||
@@ -576,6 +571,7 @@ namespace
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
|
CriticalSection ClothLocker;
|
||||||
nv::cloth::Factory* ClothFactory = nullptr;
|
nv::cloth::Factory* ClothFactory = nullptr;
|
||||||
Dictionary<nv::cloth::Fabric*, FabricSettings> Fabrics;
|
Dictionary<nv::cloth::Fabric*, FabricSettings> Fabrics;
|
||||||
Dictionary<nv::cloth::Cloth*, ClothSettings> Cloths;
|
Dictionary<nv::cloth::Cloth*, ClothSettings> Cloths;
|
||||||
@@ -708,10 +704,28 @@ void InitVehicleSDK()
|
|||||||
void ScenePhysX::PreSimulateCloth(int32 i)
|
void ScenePhysX::PreSimulateCloth(int32 i)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
auto clothPhysX = (nv::cloth::Cloth*)ClothSolver->getClothList()[i];
|
auto clothPhysX = ClothsList[i];
|
||||||
auto& clothSettings = Cloths[clothPhysX];
|
auto& clothSettings = Cloths[clothPhysX];
|
||||||
|
|
||||||
clothSettings.Actor->OnPreUpdate();
|
if (clothSettings.Actor->OnPreUpdate())
|
||||||
|
{
|
||||||
|
// Cull simulation based on distance
|
||||||
|
if (!clothSettings.Culled)
|
||||||
|
{
|
||||||
|
clothSettings.Culled = true;
|
||||||
|
ClothLocker.Lock();
|
||||||
|
ClothSolver->removeCloth(clothPhysX);
|
||||||
|
ClothLocker.Unlock();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clothSettings.Culled)
|
||||||
|
{
|
||||||
|
clothSettings.Culled = false;
|
||||||
|
ClothLocker.Lock();
|
||||||
|
ClothSolver->addCloth(clothPhysX);
|
||||||
|
ClothLocker.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
// Setup automatic scene collisions with colliders around the cloth
|
// Setup automatic scene collisions with colliders around the cloth
|
||||||
if (clothSettings.SceneCollisions && clothSettings.CollisionsUpdateFramesLeft == 0)
|
if (clothSettings.SceneCollisions && clothSettings.CollisionsUpdateFramesLeft == 0)
|
||||||
@@ -831,7 +845,7 @@ void ScenePhysX::PreSimulateCloth(int32 i)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Cloth vs Triangle collisions are too slow for real-time use
|
// Cloth vs Triangle collisions are too slow for real-time use
|
||||||
#if 0
|
#if 0
|
||||||
case PxGeometryType::eTRIANGLEMESH:
|
case PxGeometryType::eTRIANGLEMESH:
|
||||||
{
|
{
|
||||||
const PxTriangleMeshGeometry& geomTriangleMesh = (const PxTriangleMeshGeometry&)geo;
|
const PxTriangleMeshGeometry& geomTriangleMesh = (const PxTriangleMeshGeometry&)geo;
|
||||||
@@ -880,6 +894,12 @@ void ScenePhysX::PreSimulateCloth(int32 i)
|
|||||||
clothSettings.CollisionsUpdateFramesLeft--;
|
clothSettings.CollisionsUpdateFramesLeft--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScenePhysX::SimulateCloth(int32 i)
|
||||||
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
|
ClothSolver->simulateChunk(i);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void* PhysicalMaterial::GetPhysicsMaterial()
|
void* PhysicalMaterial::GetPhysicsMaterial()
|
||||||
@@ -1632,17 +1652,15 @@ void PhysicsBackend::EndSimulateScene(void* scene)
|
|||||||
|
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
nv::cloth::Solver* clothSolver = scenePhysX->ClothSolver;
|
nv::cloth::Solver* clothSolver = scenePhysX->ClothSolver;
|
||||||
if (clothSolver && clothSolver->getNumCloths() != 0)
|
if (clothSolver && scenePhysX->ClothsList.Count() != 0)
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Physics.Cloth");
|
PROFILE_CPU_NAMED("Physics.Cloth");
|
||||||
const int32 clothsCount = scenePhysX->ClothSolver->getNumCloths();
|
|
||||||
nv::cloth::Cloth* const* cloths = scenePhysX->ClothSolver->getClothList();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Pre");
|
PROFILE_CPU_NAMED("Pre");
|
||||||
Function<void(int32)> job;
|
Function<void(int32)> job;
|
||||||
job.Bind<ScenePhysX, &ScenePhysX::PreSimulateCloth>(scenePhysX);
|
job.Bind<ScenePhysX, &ScenePhysX::PreSimulateCloth>(scenePhysX);
|
||||||
JobSystem::Execute(job, clothsCount);
|
JobSystem::Execute(job, scenePhysX->ClothsList.Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1658,10 +1676,12 @@ void PhysicsBackend::EndSimulateScene(void* scene)
|
|||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Post");
|
PROFILE_CPU_NAMED("Post");
|
||||||
for (int32 i = 0; i < clothsCount; i++)
|
ScopeLock lock(ClothLocker);
|
||||||
|
for (auto clothPhysX : scenePhysX->ClothsList)
|
||||||
{
|
{
|
||||||
auto clothPhysX = (nv::cloth::Cloth*)cloths[i];
|
|
||||||
const auto& clothSettings = Cloths[clothPhysX];
|
const auto& clothSettings = Cloths[clothPhysX];
|
||||||
|
if (clothSettings.Culled)
|
||||||
|
continue;
|
||||||
clothSettings.UpdateBounds(clothPhysX);
|
clothSettings.UpdateBounds(clothPhysX);
|
||||||
clothSettings.Actor->OnPostUpdate();
|
clothSettings.Actor->OnPostUpdate();
|
||||||
}
|
}
|
||||||
@@ -3410,6 +3430,7 @@ void* PhysicsBackend::CreateCloth(const PhysicsClothDesc& desc)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Lazy-init NvCloth
|
// Lazy-init NvCloth
|
||||||
|
ScopeLock lock(ClothLocker);
|
||||||
if (ClothFactory == nullptr)
|
if (ClothFactory == nullptr)
|
||||||
{
|
{
|
||||||
nv::cloth::InitializeNvCloth(&AllocatorCallback, &ErrorCallback, &AssertCallback, &ProfilerCallback);
|
nv::cloth::InitializeNvCloth(&AllocatorCallback, &ErrorCallback, &AssertCallback, &ProfilerCallback);
|
||||||
@@ -3507,6 +3528,7 @@ void* PhysicsBackend::CreateCloth(const PhysicsClothDesc& desc)
|
|||||||
|
|
||||||
void PhysicsBackend::DestroyCloth(void* cloth)
|
void PhysicsBackend::DestroyCloth(void* cloth)
|
||||||
{
|
{
|
||||||
|
ScopeLock lock(ClothLocker);
|
||||||
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
||||||
if (--Fabrics[&clothPhysX->getFabric()].Refs == 0)
|
if (--Fabrics[&clothPhysX->getFabric()].Refs == 0)
|
||||||
Fabrics.Remove(&clothPhysX->getFabric());
|
Fabrics.Remove(&clothPhysX->getFabric());
|
||||||
@@ -3559,7 +3581,7 @@ void PhysicsBackend::SetClothSimulationSettings(void* cloth, const void* setting
|
|||||||
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
||||||
const auto& settings = *(const Cloth::SimulationSettings*)settingsPtr;
|
const auto& settings = *(const Cloth::SimulationSettings*)settingsPtr;
|
||||||
clothPhysX->setSolverFrequency(settings.SolverFrequency);
|
clothPhysX->setSolverFrequency(settings.SolverFrequency);
|
||||||
clothPhysX->setMotionConstraintScaleBias(settings.MaxDistance, 0.0f);
|
clothPhysX->setMotionConstraintScaleBias(settings.MaxParticleDistance, 0.0f);
|
||||||
clothPhysX->setWindVelocity(C2P(settings.WindVelocity));
|
clothPhysX->setWindVelocity(C2P(settings.WindVelocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3705,6 +3727,7 @@ void PhysicsBackend::SetClothPaint(void* cloth, Span<const float> value)
|
|||||||
|
|
||||||
void PhysicsBackend::AddCloth(void* scene, void* cloth)
|
void PhysicsBackend::AddCloth(void* scene, void* cloth)
|
||||||
{
|
{
|
||||||
|
ScopeLock lock(ClothLocker);
|
||||||
auto scenePhysX = (ScenePhysX*)scene;
|
auto scenePhysX = (ScenePhysX*)scene;
|
||||||
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
||||||
if (scenePhysX->ClothSolver == nullptr)
|
if (scenePhysX->ClothSolver == nullptr)
|
||||||
@@ -3713,13 +3736,20 @@ void PhysicsBackend::AddCloth(void* scene, void* cloth)
|
|||||||
ASSERT(scenePhysX->ClothSolver);
|
ASSERT(scenePhysX->ClothSolver);
|
||||||
}
|
}
|
||||||
scenePhysX->ClothSolver->addCloth(clothPhysX);
|
scenePhysX->ClothSolver->addCloth(clothPhysX);
|
||||||
|
scenePhysX->ClothsList.Add(clothPhysX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsBackend::RemoveCloth(void* scene, void* cloth)
|
void PhysicsBackend::RemoveCloth(void* scene, void* cloth)
|
||||||
{
|
{
|
||||||
|
ScopeLock lock(ClothLocker);
|
||||||
auto scenePhysX = (ScenePhysX*)scene;
|
auto scenePhysX = (ScenePhysX*)scene;
|
||||||
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
auto clothPhysX = (nv::cloth::Cloth*)cloth;
|
||||||
scenePhysX->ClothSolver->removeCloth(clothPhysX);
|
auto& clothSettings = Cloths[clothPhysX];
|
||||||
|
if (clothSettings.Culled)
|
||||||
|
clothSettings.Culled = false;
|
||||||
|
else
|
||||||
|
scenePhysX->ClothSolver->removeCloth(clothPhysX);
|
||||||
|
scenePhysX->ClothsList.Remove(clothPhysX);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user