Program Listing for File ClothMesh.cpp¶
↰ Return to documentation for file (Source\Physics\Src\Geometry\ClothMesh.cpp
)
#include "Physics/Geometry/ClothMesh.h"
#include "Physics/Geometry/GenericTypes.h"
namespace Azura {
namespace Physics {
using namespace PBD; // NOLINT
namespace {
const RawStorageFormat VERTEX_FORMAT = RawStorageFormat::R32G32B32_FLOAT;
const RawStorageFormat UV_FORMAT = RawStorageFormat::R32G32_FLOAT;
const RawStorageFormat NORMAL_FORMAT = RawStorageFormat::R32G32B32_FLOAT;
const RawStorageFormat INDEX_FORMAT = RawStorageFormat::R32_UINT;
float ComputeBendingC(const std::vector<Vector4f>& vertices, U32 dest1, U32 dest2, U32 source) {
Vector3f v1 = vertices[dest1].xyz() - vertices[source].xyz();
Vector3f v2 = vertices[dest2].xyz() - vertices[source].xyz();
return Vector3f::DotProduct(v1, v2) / Vector3f::CrossProduct(v1, v2).Length();
}
} // namespace
ClothMesh::ClothMesh(const String& assetName, AssetLocation location, Memory::Allocator& allocator, const Log& log)
: m_vertices(allocator),
m_vertexInvMass(allocator),
m_vertexAlias(allocator),
m_normals(allocator),
m_triangles(allocator),
m_uv(allocator) {
p_interface = std::make_unique<GLTFMeshInterface>(GLTFLoader::LoadFromJSON(assetName, location, log));
U32 vertexDataSize;
U32 numVertices;
U32 normalDataSize;
U32 numNormals;
U32 uvDataSize;
U32 numUV;
U32 indexDataSize;
U32 numIndices;
const auto vertexData = p_interface->GetPositionBuffer(0, 0, vertexDataSize, numVertices);
const auto normalData = p_interface->GetNormalBuffer(0, 0, normalDataSize, numNormals);
const auto uvData = p_interface->GetUVBuffer(0, 0, uvDataSize, numUV);
const auto indexData = p_interface->GetIndexBuffer(0, 0, indexDataSize, numIndices);
const U32 numTriangles = numIndices / 3;
m_vertices.Reserve(numVertices);
m_normals.Reserve(numVertices);
m_uv.Reserve(numVertices);
m_triangles.Reserve(numTriangles);
m_vertexAlias.Reserve(numVertices);
for (U32 idx = 0; idx < numVertices; ++idx) {
const U32 id0 = 3 * idx;
const U32 id1 = 3 * idx + 1;
const U32 id2 = 3 * idx + 2;
const float vx = vertexData[id0];
const float vy = vertexData[id1];
const float vz = vertexData[id2];
const float nx = normalData[id0];
const float ny = normalData[id1];
const float nz = normalData[id2];
const float uvx = uvData[2 * idx];
const float uvy = uvData[2 * idx + 1];
const Vector3f key = Vector3f(vx, vy, vz);
if (m_vertexAliasMap.find(key) == m_vertexAliasMap.end())
{
m_vertexAliasMap[key] = idx;
m_vertexAlias.PushBack(-1);
}
else
{
m_vertexAlias.PushBack(m_vertexAliasMap[key]);
}
m_vertices.EmplaceBack(vx, vy, vz);
m_normals.EmplaceBack(nx, ny, nz);
m_uv.EmplaceBack(uvx, uvy);
}
m_vertexInvMass.Reserve(m_vertices.GetSize());
for (U32 idx = 0; idx < numTriangles; ++idx) {
const U32 id0 = indexData[3 * idx];
const U32 id1 = indexData[3 * idx + 1];
const U32 id2 = indexData[3 * idx + 2];
const auto triangleIdx = U32(m_triangles.GetSize());
m_triangles.EmplaceBack(id0, id1, id2);
AddEdgeTriangleNeighbor(Edge{id0, id1}, triangleIdx);
AddEdgeTriangleNeighbor(Edge{id1, id2}, triangleIdx);
AddEdgeTriangleNeighbor(Edge{id2, id0}, triangleIdx);
}
}
U32 ClothMesh::VertexDataSize() const {
return U32(m_vertices.GetSize() * GetFormatSize(VERTEX_FORMAT));
}
U32 ClothMesh::IndexDataSize() const {
return U32(m_triangles.GetSize() * GetFormatSize(INDEX_FORMAT) * 3);
}
U32 ClothMesh::NormalDataSize() const {
return U32(m_normals.GetSize() * GetFormatSize(NORMAL_FORMAT));
}
U32 ClothMesh::UVDataSize() const {
return U32(m_vertices.GetSize() * GetFormatSize(UV_FORMAT));
}
const U8* ClothMesh::VertexData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_vertices.Data());
}
const U8* ClothMesh::IndexData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_triangles.Data());
}
const U8* ClothMesh::NormalData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_normals.Data());
}
const U8* ClothMesh::UVData() const {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const U8*>(m_uv.Data());
}
RawStorageFormat ClothMesh::GetVertexFormat() const {
return VERTEX_FORMAT;
}
RawStorageFormat ClothMesh::GetIndexFormat() const {
return INDEX_FORMAT;
}
RawStorageFormat ClothMesh::GetNormalFormat() const {
return NORMAL_FORMAT;
}
RawStorageFormat ClothMesh::GetUVFormat() const {
return UV_FORMAT;
}
void ClothMesh::SetAnchorOnIndex(U32 idx) {
m_anchorIdx.push_back(idx);
}
const Containers::Vector<float>& ClothMesh::GetVertexInverseMass() const {
return m_vertexInvMass;
}
const Containers::Vector<int>& ClothMesh::GetVertexAliases() const {
return m_vertexAlias;
}
ClothSolvingView ClothMesh::GetPBDSolvingView(Memory::Allocator& allocator) {
for (SizeType idx = 0; idx < m_vertices.GetSize(); ++idx) {
if (IsVertexAnchorPoint(idx)) {
m_vertexInvMass.PushBack(0.0f);
continue;
}
m_vertexInvMass.PushBack(1.0f);
}
U32 numBendingConstraints = 0;
for (const auto& pair : m_edgeTriangleMap) {
if (pair.second.size() != 2) {
continue;
}
++numBendingConstraints;
}
ClothSolvingView solvingView = ClothSolvingView(
m_vertices,
m_vertexInvMass,
U32(m_edgeTriangleMap.size()),
U32(m_edgeTriangleMap.size()),
numBendingConstraints,
allocator
);
U32 vertIdx = 0;
for (const auto& vertex : m_vertices) {
if (m_vertexAlias[vertIdx] != -1)
{
++vertIdx;
continue;
}
float closestDistance = std::numeric_limits<float>::max();
U32 closestAnchorIdx = 0;
for (const auto& anchorIdx : m_anchorIdx) {
const float distance = (m_vertices[anchorIdx] - vertex).Length();
if (distance < closestDistance) {
closestDistance = distance;
closestAnchorIdx = anchorIdx;
}
}
solvingView.AddConstraint(LongRangeConstraint{
ConstraintPoint{vertIdx},
ConstraintPoint{closestAnchorIdx},
closestDistance
});
++vertIdx;
}
for (const auto& pair : m_edgeTriangleMap) {
const Edge& edge = pair.first;
// Add Distance Constraint
solvingView.AddConstraint(DistanceConstraint{
ConstraintPoint{edge.m_indexA},
ConstraintPoint{edge.m_indexB},
(m_vertices[edge.m_indexA] - m_vertices[edge.m_indexB]).Length()
});
// Add Bending Constraint
if (pair.second.size() != 2) {
continue;
}
const U32 indexX0 = edge.m_indexA;
const U32 indexX1 = edge.m_indexB;
U32 indexX2 = 0;
U32 indexX3 = 0;
Vector3u tri1 = m_triangles[pair.second[0]];
Vector3u tri2 = m_triangles[pair.second[1]];
for (U32 idx = 0; idx < 3; ++idx) {
const U32 aliasIdx1 = m_vertexAlias[tri1[idx]] == -1 ? tri1[idx] : m_vertexAlias[tri1[idx]];
if (aliasIdx1 == edge.m_indexA) {
continue;
}
if (aliasIdx1 == edge.m_indexB) {
continue;
}
indexX2 = aliasIdx1;
}
for (U32 idx = 0; idx < 3; ++idx) {
const U32 aliasIdx2 = m_vertexAlias[tri2[idx]] == -1 ? tri2[idx] : m_vertexAlias[tri2[idx]];
if (aliasIdx2 == edge.m_indexA) {
continue;
}
if (aliasIdx2 == edge.m_indexB) {
continue;
}
indexX3 = aliasIdx2;
}
solvingView.AddConstraint(BendingConstraint(
m_vertices,
ConstraintPoint{indexX0},
ConstraintPoint{indexX1},
ConstraintPoint{indexX2},
ConstraintPoint{indexX3}
));
}
return solvingView;
}
U32 ClothMesh::GetVertexCount() const {
return U32(m_vertices.GetSize());
}
U32 ClothMesh::GetIndexCount() const {
return U32(m_triangles.GetSize() * 3);
}
U32 ClothMesh::TotalDataSize() const {
return VertexDataSize() + IndexDataSize() + NormalDataSize() + UVDataSize();
}
void ClothMesh::AddEdgeTriangleNeighbor(const Edge& edge, const U32 triangleIdx) {
Edge copyEdge = {};
copyEdge.m_indexA = m_vertexAlias[edge.m_indexA] == -1 ? edge.m_indexA : m_vertexAlias[edge.m_indexA];
copyEdge.m_indexB = m_vertexAlias[edge.m_indexB] == -1 ? edge.m_indexB : m_vertexAlias[edge.m_indexB];
const auto itr = m_edgeTriangleMap.find(copyEdge);
if (itr == m_edgeTriangleMap.end()) {
m_edgeTriangleMap[copyEdge] = std::vector<U32>();
m_edgeTriangleMap[copyEdge].reserve(2);
}
m_edgeTriangleMap[copyEdge].push_back(triangleIdx);
}
bool ClothMesh::IsVertexAnchorPoint(SizeType idx) const {
return std::find(m_anchorIdx.begin(), m_anchorIdx.end(), idx) != m_anchorIdx.end();
}
} // namespace Physics
} // namespace Azura