From 29abfbcdc99f6b2dd36272ab627b8e532412e318 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 24 Mar 2026 22:59:21 +0100 Subject: [PATCH] Fix Cloth with models that use compressed vertex buffer #4017 --- Source/Engine/Graphics/Models/MeshAccessor.h | 21 ++ Source/Engine/Level/Actors/AnimatedModel.cpp | 10 + Source/Engine/Level/Actors/AnimatedModel.h | 1 + .../Level/Actors/ModelInstanceActor.cpp | 6 + .../Engine/Level/Actors/ModelInstanceActor.h | 13 + Source/Engine/Level/Actors/StaticModel.cpp | 10 + Source/Engine/Level/Actors/StaticModel.h | 1 + Source/Engine/Physics/Actors/Cloth.cpp | 238 +++++++++--------- Source/Engine/Physics/Actors/Cloth.h | 2 +- 9 files changed, 186 insertions(+), 116 deletions(-) diff --git a/Source/Engine/Graphics/Models/MeshAccessor.h b/Source/Engine/Graphics/Models/MeshAccessor.h index 25fc01a1a..96ead669c 100644 --- a/Source/Engine/Graphics/Models/MeshAccessor.h +++ b/Source/Engine/Graphics/Models/MeshAccessor.h @@ -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 src); void Set(Span src); void Set(Span src); + template + void Set(const Array& dst) const + { + Set(Span(dst.Get(), dst.Count())); + } // Copies the contents of this stream into a destination data span. void CopyTo(Span dst) const; void CopyTo(Span dst) const; void CopyTo(Span dst) const; + template + void CopyTo(Array& dst) const + { + dst.Resize(GetCount()); + CopyTo(Span(dst.Get(), dst.Count())); + } }; private: diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 11497e558..ddafd215d 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -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) diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index a520d6723..f9182d115 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -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; diff --git a/Source/Engine/Level/Actors/ModelInstanceActor.cpp b/Source/Engine/Level/Actors/ModelInstanceActor.cpp index 527775bfc..b8dc3af1a 100644 --- a/Source/Engine/Level/Actors/ModelInstanceActor.cpp +++ b/Source/Engine/Level/Actors/ModelInstanceActor.cpp @@ -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& value) { WaitForModelLoad(); diff --git a/Source/Engine/Level/Actors/ModelInstanceActor.h b/Source/Engine/Level/Actors/ModelInstanceActor.h index d5e2498fb..d553d132a 100644 --- a/Source/Engine/Level/Actors/ModelInstanceActor.h +++ b/Source/Engine/Level/Actors/ModelInstanceActor.h @@ -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: /// /// Extracts mesh buffer data from CPU. Might be cached internally (eg. by Model/SkinnedModel). + /// [Deprecated in 1.12] /// /// Mesh reference. /// Buffer type @@ -120,11 +122,22 @@ public: /// The amount of items inside the result buffer. /// The result layout of the result buffer (for vertex buffers). Optional, pass null to ignore it. /// True if failed, otherwise false. + 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; } + /// + /// Resolves a given mesh reference. + /// + /// Mesh reference. + /// Mesh or null if invalid ref. + virtual MeshBase* GetMesh(const MeshReference& ref) const + { + return nullptr; + } + /// /// Gets the mesh deformation utility for this model instance (optional). /// diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 19e4e3f34..fad068bf0 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -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) diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h index 4b575a0ed..063638e14 100644 --- a/Source/Engine/Level/Actors/StaticModel.h +++ b/Source/Engine/Level/Actors/StaticModel.h @@ -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; diff --git a/Source/Engine/Physics/Actors/Cloth.cpp b/Source/Engine/Physics/Actors/Cloth.cpp index 1f833fa0e..8c9b996ce 100644 --- a/Source/Engine/Physics/Actors/Cloth.cpp +++ b/Source/Engine/Physics/Actors/Cloth.cpp @@ -208,8 +208,12 @@ void Cloth::SetPaint(Span 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 invMasses; - CalculateInvMasses(invMasses); + CalculateInvMasses(accessor, invMasses); PhysicsBackend::LockClothParticles(_cloth); PhysicsBackend::SetClothParticles(_cloth, Span(), Span(), ToSpan(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 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 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 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 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 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 deformer; deformer.Bind(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& invMasses) +void Cloth::CalculateInvMasses(MeshAccessor& accessor, Array& invMasses) { // Use per-particle max distance to evaluate which particles are immovable #if WITH_CLOTH @@ -641,29 +661,22 @@ void Cloth::CalculateInvMasses(Array& 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& invMasses) const int32 i0 = indicesData.Get()[index]; const int32 i1 = indicesData.Get()[index + 1]; const int32 i2 = indicesData.Get()[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& invMasses) const int32 i0 = indicesData.Get()[index]; const int32 i1 = indicesData.Get()[index + 1]; const int32 i2 = indicesData.Get()[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 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()[index]; - const int32 i1 = indicesData.Get()[index + 1]; - const int32 i2 = indicesData.Get()[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()[index]; + const int32 i1 = indicesData.Get()[index + 1]; + const int32 i2 = indicesData.Get()[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()[index]; - const int32 i1 = indicesData.Get()[index + 1]; - const int32 i2 = indicesData.Get()[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()[index]; + const int32 i1 = indicesData.Get()[index + 1]; + const int32 i2 = indicesData.Get()[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; + } } } } diff --git a/Source/Engine/Physics/Actors/Cloth.h b/Source/Engine/Physics/Actors/Cloth.h index f83f1c499..8d6f13370 100644 --- a/Source/Engine/Physics/Actors/Cloth.h +++ b/Source/Engine/Physics/Actors/Cloth.h @@ -371,6 +371,6 @@ private: ImplementPhysicsDebug; bool CreateCloth(); void DestroyCloth(); - void CalculateInvMasses(Array& invMasses); + void CalculateInvMasses(class MeshAccessor& accessor, Array& invMasses); void RunClothDeformer(const MeshBase* mesh, struct MeshDeformationData& deformation); };