|
|
|
@ -7,9 +7,9 @@ |
|
|
|
|
#include <omp.h> |
|
|
|
|
#include <iostream> |
|
|
|
|
|
|
|
|
|
SoftBody::SoftBody(Mesh* mesh, float compliance) : compliance(compliance) { |
|
|
|
|
SoftBody::SoftBody(Mesh* mesh, float edgeCompliance, float triangleCompliance, float tetrahedronCompliance) { |
|
|
|
|
tetgenbehavior behavior; |
|
|
|
|
behavior.parse_commandline(std::string("pYQfeza0.1").data()); |
|
|
|
|
behavior.parse_commandline(std::string("pYQfeza1").data()); |
|
|
|
|
|
|
|
|
|
tetgenio in; |
|
|
|
|
in.numberofpoints = static_cast<int>(mesh->vertices.size()); |
|
|
|
@ -67,7 +67,7 @@ SoftBody::SoftBody(Mesh* mesh, float compliance) : compliance(compliance) { |
|
|
|
|
uint32_t c = out.trifacelist[i * 3 + 2]; |
|
|
|
|
if (out.trifacemarkerlist[i] != 0) |
|
|
|
|
faces.emplace_back(Face(a, b, c)); |
|
|
|
|
constraintData.triangles.emplace_back(Triangle(Face(a, b, c), 0)); |
|
|
|
|
constraintData.triangles.emplace_back(Triangle(Face(a, b, c), 0, triangleCompliance)); |
|
|
|
|
} |
|
|
|
|
faces.shrink_to_fit(); |
|
|
|
|
|
|
|
|
@ -76,7 +76,7 @@ SoftBody::SoftBody(Mesh* mesh, float compliance) : compliance(compliance) { |
|
|
|
|
uint32_t a = out.edgelist[i * 2 + 0]; |
|
|
|
|
uint32_t b = out.edgelist[i * 2 + 1]; |
|
|
|
|
float length = glm::length(vertices[a].position - vertices[b].position); |
|
|
|
|
constraintData.edges.emplace_back(Edge(a, b, length)); |
|
|
|
|
constraintData.edges.emplace_back(Edge(a, b, length, edgeCompliance)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float density = 1; |
|
|
|
@ -104,7 +104,7 @@ SoftBody::SoftBody(Mesh* mesh, float compliance) : compliance(compliance) { |
|
|
|
|
masses[c] += pointMass; |
|
|
|
|
masses[d] += pointMass; |
|
|
|
|
|
|
|
|
|
constraintData.tetrahedra.emplace_back(Tetrahedron(a, b, c, d, volume)); |
|
|
|
|
constraintData.tetrahedra.emplace_back(Tetrahedron(a, b, c, d, volume, tetrahedronCompliance)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < masses.size(); i++){ |
|
|
|
@ -120,14 +120,14 @@ void SoftBody::applyVertexOffset(const glm::vec3 &offset) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vector<unordered_set<const Constraint *>> createPartitions(const Graph &graph){ |
|
|
|
|
vector<unordered_set<const Constraint *>> createPartitions(const Graph &graph, const vector<const Constraint *> &ordering){ |
|
|
|
|
unordered_map<const Constraint *, uint32_t> constraintToColor; |
|
|
|
|
vector<unordered_set<const Constraint *>> colorToConstraintList; |
|
|
|
|
|
|
|
|
|
for (const auto& [constraint, adjacentList] : graph){ |
|
|
|
|
for (const Constraint * constraint : ordering){ |
|
|
|
|
|
|
|
|
|
unordered_set<uint32_t> forbiddenColors; |
|
|
|
|
for (auto adjacent : adjacentList) |
|
|
|
|
for (auto adjacent : graph.at(constraint)) |
|
|
|
|
if (constraintToColor.contains(adjacent)) |
|
|
|
|
forbiddenColors.insert(constraintToColor.at(adjacent)); |
|
|
|
|
|
|
|
|
@ -154,6 +154,41 @@ vector<unordered_set<const Constraint *>> createPartitions(const Graph &graph){ |
|
|
|
|
return colorToConstraintList; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vector<const Constraint *> smallestLastOrdering(const Graph &graph) { |
|
|
|
|
vector<const Constraint *> ordering(graph.size()); |
|
|
|
|
|
|
|
|
|
unordered_map<size_t, unordered_set<const Constraint *>> degreesToConstraints; |
|
|
|
|
unordered_map<const Constraint *, size_t> constraintsToDegrees; |
|
|
|
|
for (const auto &[constraint, adjacent] : graph) { |
|
|
|
|
degreesToConstraints[adjacent.size()].insert(constraint); |
|
|
|
|
constraintsToDegrees[constraint] = adjacent.size(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto iter = ordering.rbegin(); iter != ordering.rend(); iter++) { |
|
|
|
|
size_t minDegree = 0; |
|
|
|
|
while (degreesToConstraints[minDegree].empty()) |
|
|
|
|
minDegree++; |
|
|
|
|
const Constraint * minConstraint = *degreesToConstraints[minDegree].begin(); |
|
|
|
|
degreesToConstraints[minDegree].erase(minConstraint); |
|
|
|
|
constraintsToDegrees.erase(minConstraint); |
|
|
|
|
|
|
|
|
|
for (const auto &neighbor: graph.at(minConstraint)) { |
|
|
|
|
if (constraintsToDegrees.contains(neighbor)) { |
|
|
|
|
size_t oldDegree = constraintsToDegrees[neighbor]; |
|
|
|
|
size_t newDegree = oldDegree - 1; |
|
|
|
|
|
|
|
|
|
constraintsToDegrees[neighbor] = newDegree; |
|
|
|
|
degreesToConstraints[oldDegree].erase(neighbor); |
|
|
|
|
degreesToConstraints[newDegree].insert(neighbor); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
*iter = minConstraint; |
|
|
|
|
} |
|
|
|
|
return ordering; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SoftBody::splitConstraints() { |
|
|
|
|
omp_set_num_threads(omp_get_num_procs() - 2); |
|
|
|
|
|
|
|
|
@ -210,7 +245,9 @@ void SoftBody::splitConstraints() { |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vector<unordered_set<const Constraint *>> partitions = createPartitions(graph); |
|
|
|
|
auto ordering = smallestLastOrdering(graph); |
|
|
|
|
|
|
|
|
|
vector<unordered_set<const Constraint *>> partitions = createPartitions(graph, ordering); |
|
|
|
|
constraintData.partitionCount = partitions.size(); |
|
|
|
|
|
|
|
|
|
reorderConstraintIndices(partitions); |
|
|
|
@ -228,8 +265,4 @@ void SoftBody::reorderConstraintIndices(const vector<unordered_set<const Constra |
|
|
|
|
std::swap(reordered.tetrahedronPartitions, constraintData.tetrahedronPartitions); |
|
|
|
|
std::swap(reordered.edges, constraintData.edges); |
|
|
|
|
std::swap(reordered.tetrahedra, constraintData.tetrahedra); |
|
|
|
|
//std::swap(reordered, constraintData);
|
|
|
|
|
//reordered.triangles.swap(constraintData.triangles);
|
|
|
|
|
//reordered.tetrahedra.swap(constraintData.tetrahedra);
|
|
|
|
|
//std::swap(reordered.partitionCount, constraintData.partitionCount);
|
|
|
|
|
} |
|
|
|
|