@@ -39,51 +39,61 @@ public:
|
||||
|
||||
FORCE_INLINE int32 GetInt(int32 index) const
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
return (int32)_sampler.Read(_data.Get() + index * _stride).X;
|
||||
}
|
||||
|
||||
FORCE_INLINE float GetFloat(int32 index) const
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
return _sampler.Read(_data.Get() + index * _stride).X;
|
||||
}
|
||||
|
||||
FORCE_INLINE Float2 GetFloat2(int32 index) const
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
return Float2(_sampler.Read(_data.Get() + index * _stride));
|
||||
}
|
||||
|
||||
FORCE_INLINE Float3 GetFloat3(int32 index) const
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
return Float3(_sampler.Read(_data.Get() + index * _stride));
|
||||
}
|
||||
|
||||
FORCE_INLINE Float4 GetFloat4(int32 index) const
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
return _sampler.Read(_data.Get() + index * _stride);
|
||||
}
|
||||
|
||||
FORCE_INLINE void SetInt(int32 index, const int32 value)
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
_sampler.Write(_data.Get() + index * _stride, Float4((float)value));
|
||||
}
|
||||
|
||||
FORCE_INLINE void SetFloat(int32 index, const float value)
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
_sampler.Write(_data.Get() + index * _stride, Float4(value));
|
||||
}
|
||||
|
||||
FORCE_INLINE void SetFloat2(int32 index, const Float2& value)
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
_sampler.Write(_data.Get() + index * _stride, Float4(value));
|
||||
}
|
||||
|
||||
FORCE_INLINE void SetFloat3(int32 index, const Float3& value)
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
_sampler.Write(_data.Get() + index * _stride, Float4(value));
|
||||
}
|
||||
|
||||
FORCE_INLINE void SetFloat4(int32 index, const Float4& value)
|
||||
{
|
||||
ASSERT_LOW_LAYER(index * _stride < _data.Length());
|
||||
_sampler.Write(_data.Get() + index * _stride, value);
|
||||
}
|
||||
|
||||
@@ -94,11 +104,22 @@ public:
|
||||
void Set(Span<Float2> src);
|
||||
void Set(Span<Float3> src);
|
||||
void Set(Span<Color> src);
|
||||
template<typename T>
|
||||
void Set(const Array<T>& dst) const
|
||||
{
|
||||
Set(Span<T>(dst.Get(), dst.Count()));
|
||||
}
|
||||
|
||||
// Copies the contents of this stream into a destination data span.
|
||||
void CopyTo(Span<Float2> dst) const;
|
||||
void CopyTo(Span<Float3> dst) const;
|
||||
void CopyTo(Span<Color> dst) const;
|
||||
template<typename T>
|
||||
void CopyTo(Array<T>& dst) const
|
||||
{
|
||||
dst.Resize(GetCount());
|
||||
CopyTo(Span<T>(dst.Get(), dst.Count()));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -1397,6 +1397,16 @@ bool AnimatedModel::GetMeshData(const MeshReference& ref, MeshBufferType type, B
|
||||
return mesh.DownloadDataCPU(type, result, count, layout);
|
||||
}
|
||||
|
||||
MeshBase* AnimatedModel::GetMesh(const MeshReference& ref) const
|
||||
{
|
||||
const auto model = SkinnedModel.Get();
|
||||
if (!model || model->WaitForLoaded())
|
||||
return nullptr;
|
||||
auto& lod = model->LODs[Math::Min(ref.LODIndex, model->LODs.Count() - 1)];
|
||||
auto& mesh = lod.Meshes[Math::Min(ref.MeshIndex, lod.Meshes.Count() - 1)];
|
||||
return &mesh;
|
||||
}
|
||||
|
||||
MeshDeformation* AnimatedModel::GetMeshDeformation() const
|
||||
{
|
||||
if (!_deformation)
|
||||
|
||||
@@ -479,6 +479,7 @@ public:
|
||||
bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override;
|
||||
bool GetMeshData(const MeshReference& ref, MeshBufferType type, BytesContainer& result, int32& count, GPUVertexLayout** layout) const override;
|
||||
MeshBase* GetMesh(const MeshReference& ref) const override;
|
||||
void UpdateBounds() override;
|
||||
MeshDeformation* GetMeshDeformation() const override;
|
||||
void OnDeleteObject() override;
|
||||
|
||||
@@ -14,6 +14,12 @@ String ModelInstanceActor::MeshReference::ToString() const
|
||||
return String::Format(TEXT("Actor={},LOD={},Mesh={}"), Actor ? Actor->GetNamePath() : String::Empty, LODIndex, MeshIndex);
|
||||
}
|
||||
|
||||
MeshBase* ModelInstanceActor::MeshReference::Get() const
|
||||
{
|
||||
auto actor = Actor.Get();
|
||||
return actor ? actor->GetMesh(*this) : nullptr;
|
||||
}
|
||||
|
||||
void ModelInstanceActor::SetEntries(const Array<ModelInstanceEntry>& value)
|
||||
{
|
||||
WaitForModelLoad();
|
||||
|
||||
@@ -29,6 +29,7 @@ API_CLASS(Abstract) class FLAXENGINE_API ModelInstanceActor : public Actor
|
||||
API_FIELD() int32 MeshIndex = 0;
|
||||
|
||||
String ToString() const;
|
||||
MeshBase* Get() const;
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -113,6 +114,7 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// Extracts mesh buffer data from CPU. Might be cached internally (eg. by Model/SkinnedModel).
|
||||
/// [Deprecated in 1.12]
|
||||
/// </summary>
|
||||
/// <param name="ref">Mesh reference.</param>
|
||||
/// <param name="type">Buffer type</param>
|
||||
@@ -120,11 +122,22 @@ public:
|
||||
/// <param name="count">The amount of items inside the result buffer.</param>
|
||||
/// <param name="layout">The result layout of the result buffer (for vertex buffers). Optional, pass null to ignore it.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
DEPRECATED("Use GetMesh to resolve mesh reference and access mesh data with MeshAccessor.")
|
||||
virtual bool GetMeshData(const MeshReference& ref, MeshBufferType type, BytesContainer& result, int32& count, GPUVertexLayout** layout = nullptr) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a given mesh reference.
|
||||
/// </summary>
|
||||
/// <param name="ref">Mesh reference.</param>
|
||||
/// <returns>Mesh or null if invalid ref.</returns>
|
||||
virtual MeshBase* GetMesh(const MeshReference& ref) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mesh deformation utility for this model instance (optional).
|
||||
/// </summary>
|
||||
|
||||
@@ -665,6 +665,16 @@ bool StaticModel::GetMeshData(const MeshReference& ref, MeshBufferType type, Byt
|
||||
return mesh.DownloadDataCPU(type, result, count, layout);
|
||||
}
|
||||
|
||||
MeshBase* StaticModel::GetMesh(const MeshReference& ref) const
|
||||
{
|
||||
const auto model = Model.Get();
|
||||
if (!model || model->WaitForLoaded())
|
||||
return nullptr;
|
||||
auto& lod = model->LODs[Math::Min(ref.LODIndex, model->LODs.Count() - 1)];
|
||||
auto& mesh = lod.Meshes[Math::Min(ref.MeshIndex, lod.Meshes.Count() - 1)];
|
||||
return &mesh;
|
||||
}
|
||||
|
||||
MeshDeformation* StaticModel::GetMeshDeformation() const
|
||||
{
|
||||
if (!_deformation)
|
||||
|
||||
@@ -181,6 +181,7 @@ public:
|
||||
bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override;
|
||||
bool GetMeshData(const MeshReference& ref, MeshBufferType type, BytesContainer& result, int32& count, GPUVertexLayout** layout) const override;
|
||||
MeshBase* GetMesh(const MeshReference& ref) const override;
|
||||
MeshDeformation* GetMeshDeformation() const override;
|
||||
void UpdateBounds() override;
|
||||
|
||||
|
||||
@@ -208,8 +208,12 @@ void Cloth::SetPaint(Span<const float> value)
|
||||
if (_cloth)
|
||||
{
|
||||
// Update cloth particles
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[2] = { MeshBufferType::Index, MeshBufferType::Vertex0 };
|
||||
if (accessor.LoadMesh(GetMesh().Get(), false, ToSpan(bufferTypes, 2)))
|
||||
return;
|
||||
Array<float> invMasses;
|
||||
CalculateInvMasses(invMasses);
|
||||
CalculateInvMasses(accessor, invMasses);
|
||||
PhysicsBackend::LockClothParticles(_cloth);
|
||||
PhysicsBackend::SetClothParticles(_cloth, Span<const Float4>(), Span<const Float3>(), ToSpan<float, const float>(invMasses));
|
||||
PhysicsBackend::SetClothPaint(_cloth, value);
|
||||
@@ -227,18 +231,20 @@ bool Cloth::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
|
||||
if (_cloth)
|
||||
{
|
||||
// Precise per-triangle intersection
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
const ModelInstanceActor::MeshReference meshRef = GetMesh();
|
||||
if (meshRef.Actor == nullptr)
|
||||
return false;
|
||||
BytesContainer indicesData;
|
||||
int32 indicesCount;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Index, indicesData, indicesCount))
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[1] = { MeshBufferType::Index };
|
||||
if (accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 1)))
|
||||
return false;
|
||||
auto indices = accessor.Index();
|
||||
auto indicesData = indices.GetData();
|
||||
PhysicsBackend::LockClothParticles(_cloth);
|
||||
const Span<const Float4> particles = PhysicsBackend::GetClothParticles(_cloth);
|
||||
const Transform transform = GetTransform();
|
||||
const bool indices16bit = indicesData.Length() / indicesCount == sizeof(uint16);
|
||||
const int32 trianglesCount = indicesCount / 3;
|
||||
const bool indices16bit = indices.GetFormat() == PixelFormat::R16_UInt;
|
||||
const int32 trianglesCount = indices.GetCount() / 3;
|
||||
bool result = false;
|
||||
distance = MAX_Real;
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
@@ -341,18 +347,20 @@ void Cloth::DrawPhysicsDebug(RenderView& view)
|
||||
if (_cloth)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
const ModelInstanceActor::MeshReference meshRef = GetMesh();
|
||||
if (meshRef.Actor == nullptr)
|
||||
return;
|
||||
BytesContainer indicesData;
|
||||
int32 indicesCount;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Index, indicesData, indicesCount))
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[1] = { MeshBufferType::Index };
|
||||
if (accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 1)))
|
||||
return;
|
||||
auto indices = accessor.Index();
|
||||
auto indicesData = indices.GetData();
|
||||
PhysicsBackend::LockClothParticles(_cloth);
|
||||
const Span<const Float4> particles = PhysicsBackend::GetClothParticles(_cloth);
|
||||
const Transform transform = GetTransform();
|
||||
const bool indices16bit = indicesData.Length() / indicesCount == sizeof(uint16);
|
||||
const int32 trianglesCount = indicesCount / 3;
|
||||
const bool indices16bit = indices.GetFormat() == PixelFormat::R16_UInt;
|
||||
const int32 trianglesCount = indices.GetCount() / 3;
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
{
|
||||
const int32 index = triangleIndex * 3;
|
||||
@@ -390,18 +398,20 @@ void Cloth::OnDebugDrawSelected()
|
||||
if (_cloth)
|
||||
{
|
||||
DEBUG_DRAW_WIRE_BOX(_box, Color::Violet.RGBMultiplied(0.8f), 0, true);
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
const ModelInstanceActor::MeshReference meshRef = GetMesh();
|
||||
if (meshRef.Actor == nullptr)
|
||||
return;
|
||||
BytesContainer indicesData;
|
||||
int32 indicesCount;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Index, indicesData, indicesCount))
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[1] = { MeshBufferType::Index };
|
||||
if (accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 1)))
|
||||
return;
|
||||
auto indices = accessor.Index();
|
||||
auto indicesData = indices.GetData();
|
||||
PhysicsBackend::LockClothParticles(_cloth);
|
||||
const Span<const Float4> particles = PhysicsBackend::GetClothParticles(_cloth);
|
||||
const Transform transform = GetTransform();
|
||||
const bool indices16bit = indicesData.Length() / indicesCount == sizeof(uint16);
|
||||
const int32 trianglesCount = indicesCount / 3;
|
||||
const bool indices16bit = indices.GetFormat() == PixelFormat::R16_UInt;
|
||||
const int32 trianglesCount = indices.GetCount() / 3;
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
{
|
||||
const int32 index = triangleIndex * 3;
|
||||
@@ -556,26 +566,36 @@ bool Cloth::CreateCloth()
|
||||
|
||||
// Get mesh data
|
||||
// TODO: consider making it via async task so physics can wait on the cloth setup from mesh data just before next fixed update which gives more time when loading scene
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
const ModelInstanceActor::MeshReference meshRef = GetMesh();
|
||||
if (meshRef.Actor == nullptr)
|
||||
return false;
|
||||
PhysicsClothDesc desc;
|
||||
desc.Actor = this;
|
||||
BytesContainer data;
|
||||
int32 count;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Vertex0, data, count))
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[2] = { MeshBufferType::Index, MeshBufferType::Vertex0 };
|
||||
if (accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 2)))
|
||||
return true;
|
||||
// TODO: use MeshAccessor vertex data layout descriptor instead hardcoded position data at the beginning of VB0
|
||||
desc.VerticesData = data.Get();
|
||||
desc.VerticesCount = count;
|
||||
desc.VerticesStride = data.Length() / count;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Index, data, count))
|
||||
return true;
|
||||
desc.IndicesData = data.Get();
|
||||
desc.IndicesCount = count;
|
||||
desc.IndicesStride = data.Length() / count;
|
||||
auto position = accessor.Position();
|
||||
Array<Float3> tempPositions;
|
||||
if (position.GetFormat() == PixelFormat::R32G32B32_Float)
|
||||
{
|
||||
desc.VerticesData = position.GetData().Get();
|
||||
desc.VerticesCount = position.GetCount();
|
||||
desc.VerticesStride = position.GetStride();
|
||||
}
|
||||
else
|
||||
{
|
||||
position.CopyTo(tempPositions);
|
||||
desc.VerticesData = tempPositions.Get();
|
||||
desc.VerticesCount = tempPositions.Count();
|
||||
desc.VerticesStride = sizeof(Float3);
|
||||
}
|
||||
auto indices = accessor.Index();
|
||||
desc.IndicesData = indices.GetData().Get();
|
||||
desc.IndicesCount = indices.GetCount();
|
||||
desc.IndicesStride = indices.GetStride();
|
||||
Array<float> invMasses;
|
||||
CalculateInvMasses(invMasses);
|
||||
CalculateInvMasses(accessor, invMasses);
|
||||
desc.InvMassesData = invMasses.Count() == desc.VerticesCount ? invMasses.Get() : nullptr;
|
||||
desc.InvMassesStride = sizeof(float);
|
||||
desc.MaxDistancesData = _paint.Count() == desc.VerticesCount ? _paint.Get() : nullptr;
|
||||
@@ -595,13 +615,13 @@ bool Cloth::CreateCloth()
|
||||
PhysicsBackend::ClearClothInertia(_cloth);
|
||||
|
||||
// Add cloth mesh deformer
|
||||
if (auto* deformation = mesh.Actor->GetMeshDeformation())
|
||||
if (auto* deformation = meshRef.Actor->GetMeshDeformation())
|
||||
{
|
||||
Function<void(const MeshBase*, MeshDeformationData&)> deformer;
|
||||
deformer.Bind<Cloth, &Cloth::RunClothDeformer>(this);
|
||||
deformation->AddDeformer(mesh.LODIndex, mesh.MeshIndex, MeshBufferType::Vertex0, deformer);
|
||||
deformation->AddDeformer(meshRef.LODIndex, meshRef.MeshIndex, MeshBufferType::Vertex0, deformer);
|
||||
if (_simulationSettings.ComputeNormals)
|
||||
deformation->AddDeformer(mesh.LODIndex, mesh.MeshIndex, MeshBufferType::Vertex1, deformer);
|
||||
deformation->AddDeformer(meshRef.LODIndex, meshRef.MeshIndex, MeshBufferType::Vertex1, deformer);
|
||||
_meshDeformation = deformation;
|
||||
}
|
||||
|
||||
@@ -631,7 +651,7 @@ void Cloth::DestroyCloth()
|
||||
#endif
|
||||
}
|
||||
|
||||
void Cloth::CalculateInvMasses(Array<float>& invMasses)
|
||||
void Cloth::CalculateInvMasses(MeshAccessor& accessor, Array<float>& invMasses)
|
||||
{
|
||||
// Use per-particle max distance to evaluate which particles are immovable
|
||||
#if WITH_CLOTH
|
||||
@@ -641,29 +661,22 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
|
||||
PROFILE_MEM(Physics);
|
||||
|
||||
// Get mesh data
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
return;
|
||||
BytesContainer verticesData;
|
||||
int32 verticesCount;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Vertex0, verticesData, verticesCount))
|
||||
return;
|
||||
BytesContainer indicesData;
|
||||
int32 indicesCount;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Index, indicesData, indicesCount))
|
||||
return;
|
||||
auto positions = accessor.Position();
|
||||
auto indices = accessor.Index();
|
||||
CHECK(positions.IsValid() && indices.IsValid());
|
||||
int32 verticesCount = positions.GetCount();
|
||||
if (_paint.Count() != verticesCount)
|
||||
{
|
||||
// Fix incorrect paint data
|
||||
LOG(Warning, "Incorrect cloth '{}' paint size {} for mesh '{}' that has {} vertices", GetNamePath(), _paint.Count(), mesh.ToString(), verticesCount);
|
||||
LOG(Warning, "Incorrect cloth '{}' paint size {} for mesh '{}' that has {} vertices", GetNamePath(), _paint.Count(), GetMesh().ToString(), verticesCount);
|
||||
int32 countBefore = _paint.Count();
|
||||
_paint.Resize(verticesCount);
|
||||
for (int32 i = countBefore; i < verticesCount; i++)
|
||||
_paint.Get()[i] = 0.0f;
|
||||
}
|
||||
const int32 verticesStride = verticesData.Length() / verticesCount;
|
||||
const bool indices16bit = indicesData.Length() / indicesCount == sizeof(uint16);
|
||||
const int32 trianglesCount = indicesCount / 3;
|
||||
const bool indices16bit = indices.GetFormat() == PixelFormat::R16_UInt;
|
||||
const int32 trianglesCount = indices.GetCount() / 3;
|
||||
auto indicesData = indices.GetData();
|
||||
|
||||
// Sum triangle area for each influenced particle
|
||||
invMasses.Resize(verticesCount);
|
||||
@@ -676,12 +689,9 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
|
||||
const int32 i0 = indicesData.Get<uint16>()[index];
|
||||
const int32 i1 = indicesData.Get<uint16>()[index + 1];
|
||||
const int32 i2 = indicesData.Get<uint16>()[index + 2];
|
||||
// TODO: use MeshAccessor vertex data layout descriptor instead hardcoded position data at the beginning of VB0
|
||||
#define GET_POS(i) *(Float3*)((byte*)verticesData.Get() + i * verticesStride)
|
||||
const Float3 v0(GET_POS(i0));
|
||||
const Float3 v1(GET_POS(i1));
|
||||
const Float3 v2(GET_POS(i2));
|
||||
#undef GET_POS
|
||||
const Float3 v0(positions.GetFloat3(i0));
|
||||
const Float3 v1(positions.GetFloat3(i1));
|
||||
const Float3 v2(positions.GetFloat3(i2));
|
||||
const float area = Float3::TriangleArea(v0, v1, v2);
|
||||
invMasses.Get()[i0] += area;
|
||||
invMasses.Get()[i1] += area;
|
||||
@@ -696,12 +706,9 @@ void Cloth::CalculateInvMasses(Array<float>& invMasses)
|
||||
const int32 i0 = indicesData.Get<uint32>()[index];
|
||||
const int32 i1 = indicesData.Get<uint32>()[index + 1];
|
||||
const int32 i2 = indicesData.Get<uint32>()[index + 2];
|
||||
// TODO: use MeshAccessor vertex data layout descriptor instead hardcoded position data at the beginning of VB0
|
||||
#define GET_POS(i) *(Float3*)((byte*)verticesData.Get() + i * verticesStride)
|
||||
const Float3 v0(GET_POS(i0));
|
||||
const Float3 v1(GET_POS(i1));
|
||||
const Float3 v2(GET_POS(i2));
|
||||
#undef GET_POS
|
||||
const Float3 v0(positions.GetFloat3(i0));
|
||||
const Float3 v1(positions.GetFloat3(i1));
|
||||
const Float3 v2(positions.GetFloat3(i2));
|
||||
const float area = Float3::TriangleArea(v0, v1, v2);
|
||||
invMasses.Get()[i0] += area;
|
||||
invMasses.Get()[i1] += area;
|
||||
@@ -787,25 +794,22 @@ bool Cloth::OnPreUpdate()
|
||||
{
|
||||
if (animatedModel->GraphInstance.NodesPose.IsEmpty() || _paint.IsEmpty())
|
||||
return false;
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
return false;
|
||||
BytesContainer verticesData;
|
||||
int32 verticesCount;
|
||||
GPUVertexLayout* layout;
|
||||
if (mesh.Actor->GetMeshData(mesh, MeshBufferType::Vertex0, verticesData, verticesCount, &layout))
|
||||
const ModelInstanceActor::MeshReference meshRef = GetMesh();
|
||||
if (meshRef.Actor == nullptr)
|
||||
return false;
|
||||
MeshAccessor accessor;
|
||||
if (accessor.LoadBuffer(MeshBufferType::Vertex0, verticesData, layout))
|
||||
MeshBufferType bufferTypes[1] = { MeshBufferType::Vertex0 };
|
||||
if (accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 1)))
|
||||
return false;
|
||||
auto positionStream = accessor.Position();
|
||||
auto blendIndicesStream = accessor.BlendIndices();
|
||||
auto blendWeightsStream = accessor.BlendWeights();
|
||||
if (!positionStream.IsValid() || !blendIndicesStream.IsValid() || !blendWeightsStream.IsValid())
|
||||
return false;
|
||||
const int32 verticesCount = positionStream.GetCount();
|
||||
if (verticesCount != _paint.Count())
|
||||
{
|
||||
LOG(Warning, "Incorrect cloth '{}' paint size {} for mesh '{}' that has {} vertices", GetNamePath(), _paint.Count(), mesh.ToString(), verticesCount);
|
||||
LOG(Warning, "Incorrect cloth '{}' paint size {} for mesh '{}' that has {} vertices", GetNamePath(), _paint.Count(), meshRef.ToString(), verticesCount);
|
||||
return false;
|
||||
}
|
||||
PROFILE_CPU_NAMED("Skinned Pose");
|
||||
@@ -934,49 +938,53 @@ void Cloth::RunClothDeformer(const MeshBase* mesh, MeshDeformationData& deformat
|
||||
// Calculate normals
|
||||
Array<Float3> normals;
|
||||
const ModelInstanceActor::MeshReference meshRef = GetMesh();
|
||||
BytesContainer indicesData;
|
||||
int32 indicesCount;
|
||||
if ((_simulationSettings.ComputeNormals || deformation.Type == MeshBufferType::Vertex1) &&
|
||||
meshRef.Actor && !meshRef.Actor->GetMeshData(meshRef, MeshBufferType::Index, indicesData, indicesCount))
|
||||
if ((_simulationSettings.ComputeNormals || deformation.Type == MeshBufferType::Vertex1) && meshRef.Actor)
|
||||
{
|
||||
PROFILE_CPU_NAMED("Normals");
|
||||
// TODO: optimize memory allocs (eg. use shared allocator)
|
||||
normals.Resize(vbCount);
|
||||
Platform::MemoryClear(normals.Get(), vbCount * sizeof(Float3));
|
||||
const bool indices16bit = indicesData.Length() / indicesCount == sizeof(uint16);
|
||||
const int32 trianglesCount = indicesCount / 3;
|
||||
if (indices16bit)
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[1] = { MeshBufferType::Index };
|
||||
if (!accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 1)))
|
||||
{
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
PROFILE_CPU_NAMED("Normals");
|
||||
auto indices = accessor.Index();
|
||||
auto indicesData = indices.GetData();
|
||||
// TODO: optimize memory allocs (eg. use shared allocator)
|
||||
normals.Resize(vbCount);
|
||||
Platform::MemoryClear(normals.Get(), vbCount * sizeof(Float3));
|
||||
const bool indices16bit = indices.GetFormat() == PixelFormat::R16_UInt;
|
||||
const int32 trianglesCount = indices.GetCount() / 3;
|
||||
if (indices16bit)
|
||||
{
|
||||
const int32 index = triangleIndex * 3;
|
||||
const int32 i0 = indicesData.Get<uint16>()[index];
|
||||
const int32 i1 = indicesData.Get<uint16>()[index + 1];
|
||||
const int32 i2 = indicesData.Get<uint16>()[index + 2];
|
||||
const Float3 v0(particles.Get()[i0]);
|
||||
const Float3 v1(particles.Get()[i1]);
|
||||
const Float3 v2(particles.Get()[i2]);
|
||||
const Float3 normal = Float3::Cross(v1 - v0, v2 - v0);
|
||||
normals.Get()[i0] += normal;
|
||||
normals.Get()[i1] += normal;
|
||||
normals.Get()[i2] += normal;
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
{
|
||||
const int32 index = triangleIndex * 3;
|
||||
const int32 i0 = indicesData.Get<uint16>()[index];
|
||||
const int32 i1 = indicesData.Get<uint16>()[index + 1];
|
||||
const int32 i2 = indicesData.Get<uint16>()[index + 2];
|
||||
const Float3 v0(particles.Get()[i0]);
|
||||
const Float3 v1(particles.Get()[i1]);
|
||||
const Float3 v2(particles.Get()[i2]);
|
||||
const Float3 normal = Float3::Cross(v1 - v0, v2 - v0);
|
||||
normals.Get()[i0] += normal;
|
||||
normals.Get()[i1] += normal;
|
||||
normals.Get()[i2] += normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
else
|
||||
{
|
||||
const int32 index = triangleIndex * 3;
|
||||
const int32 i0 = indicesData.Get<uint32>()[index];
|
||||
const int32 i1 = indicesData.Get<uint32>()[index + 1];
|
||||
const int32 i2 = indicesData.Get<uint32>()[index + 2];
|
||||
const Float3 v0(particles.Get()[i0]);
|
||||
const Float3 v1(particles.Get()[i1]);
|
||||
const Float3 v2(particles.Get()[i2]);
|
||||
const Float3 normal = Float3::Cross(v1 - v0, v2 - v0);
|
||||
normals.Get()[i0] += normal;
|
||||
normals.Get()[i1] += normal;
|
||||
normals.Get()[i2] += normal;
|
||||
for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++)
|
||||
{
|
||||
const int32 index = triangleIndex * 3;
|
||||
const int32 i0 = indicesData.Get<uint32>()[index];
|
||||
const int32 i1 = indicesData.Get<uint32>()[index + 1];
|
||||
const int32 i2 = indicesData.Get<uint32>()[index + 2];
|
||||
const Float3 v0(particles.Get()[i0]);
|
||||
const Float3 v1(particles.Get()[i1]);
|
||||
const Float3 v2(particles.Get()[i2]);
|
||||
const Float3 normal = Float3::Cross(v1 - v0, v2 - v0);
|
||||
normals.Get()[i0] += normal;
|
||||
normals.Get()[i1] += normal;
|
||||
normals.Get()[i2] += normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +371,6 @@ private:
|
||||
ImplementPhysicsDebug;
|
||||
bool CreateCloth();
|
||||
void DestroyCloth();
|
||||
void CalculateInvMasses(Array<float>& invMasses);
|
||||
void CalculateInvMasses(class MeshAccessor& accessor, Array<float>& invMasses);
|
||||
void RunClothDeformer(const MeshBase* mesh, struct MeshDeformationData& deformation);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user