2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-05-25 02:51:43 +00:00

feat: calculate model collision tree with leafs

This commit is contained in:
Jan Laupetin
2026-05-21 18:24:51 +02:00
parent a128fbeb5e
commit 5cf0ce37c1
7 changed files with 268 additions and 9 deletions
@@ -0,0 +1,116 @@
#include "CollisionTreeCreator.h"
#include <cassert>
namespace
{
class Bounds
{
public:
Bounds()
: m_mins(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
m_maxs(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min())
{
}
void ExpandFromTri(const std::array<Eigen::Vector3f, 3>& triCoordinates)
{
for (const auto& vert : triCoordinates)
{
m_mins[0] = std::min(m_mins[0], vert.x());
m_mins[1] = std::min(m_mins[1], vert.y());
m_mins[2] = std::min(m_mins[2], vert.z());
m_maxs[0] = std::max(m_maxs[0], vert.x());
m_maxs[1] = std::max(m_maxs[1], vert.y());
m_maxs[2] = std::max(m_maxs[2], vert.z());
}
}
void ExpandFromBounds(const Bounds& otherBounds)
{
m_mins[0] = std::min(m_mins[0], otherBounds.m_mins[0]);
m_mins[1] = std::min(m_mins[1], otherBounds.m_mins[1]);
m_mins[2] = std::min(m_mins[2], otherBounds.m_mins[2]);
m_maxs[0] = std::min(m_maxs[0], otherBounds.m_maxs[0]);
m_maxs[1] = std::min(m_maxs[1], otherBounds.m_maxs[1]);
m_maxs[2] = std::min(m_maxs[2], otherBounds.m_maxs[2]);
}
[[nodiscard]] Eigen::Vector3f GetDelta() const
{
return m_maxs - m_mins;
}
[[nodiscard]] float GetVolume() const
{
return GetDelta().prod();
}
Eigen::Vector3f m_mins;
Eigen::Vector3f m_maxs;
};
} // namespace
namespace xmodel
{
std::unique_ptr<CommonCollisionTree> CreateCollisionTree(const IRigidVertListAccessor& vertList)
{
auto tree = std::make_unique<CommonCollisionTree>();
Bounds globalBounds;
const auto triOffset = vertList.GetTriOffset();
const auto triCount = vertList.GetTriCount();
std::vector<Bounds> leafBounds;
auto lastMergeable = false;
Bounds prevBounds;
for (size_t triNumber = 0; triNumber < triCount; triNumber++)
{
const auto triIndex = triOffset + triNumber;
Bounds triBounds;
triBounds.ExpandFromTri(vertList.GetCoordinatesForTri(triIndex));
globalBounds.ExpandFromBounds(triBounds);
auto shouldMerge = false;
if (lastMergeable)
{
const auto prevVolume = prevBounds.GetVolume();
const auto thisVolume = triBounds.GetVolume();
prevBounds.ExpandFromBounds(triBounds);
const auto combinedVolume = prevBounds.GetVolume();
if (combinedVolume <= prevVolume + thisVolume)
shouldMerge = true;
}
if (shouldMerge)
{
leafBounds.back() = prevBounds;
assert(!tree->leafs.back().twoTriangles);
tree->leafs.back().twoTriangles = 1;
lastMergeable = false;
}
else
{
tree->leafs.emplace_back(CommonCollisionLeaf{
.triangleBeginIndex = static_cast<decltype(CommonCollisionLeaf::triangleBeginIndex)>(triIndex),
.twoTriangles = 0,
});
leafBounds.emplace_back(triBounds);
lastMergeable = true;
prevBounds = triBounds;
}
}
tree->trans = -globalBounds.m_mins;
const auto globalDelta = globalBounds.GetDelta();
tree->scale = Eigen::Vector3f(std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max())
.cwiseQuotient(globalDelta);
// TODO: Calculate nodes
return std::move(tree);
}
} // namespace xmodel