Skip to content

Commit

Permalink
--expand calculation to test for mesh topology - watertight and manif…
Browse files Browse the repository at this point in the history
…old.
  • Loading branch information
jturner65 committed Aug 29, 2024
1 parent 484f107 commit fc9edba
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 27 deletions.
99 changes: 74 additions & 25 deletions src/esp/assets/ResourceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1058,37 +1058,86 @@ void ResourceManager::computeGeneralMeshAreaAndVolume(
meshData->positions3DAsArray(0);
Mn::MeshTools::transformPointsInPlace(absTransforms[iEntry], posArray);

// Getting the view properly relies on having the appropriate type of the
// loaded data
// const auto idxView = meshData->indices<std::uint32_t>();
const auto idxAra = meshData->indicesAsArray();
// # of indices
uint32_t numIdxs = meshData->indexCount();
// Assuming no duplicate vertices with different idxs
// Determine that all edges have exactly 2 sides ->
// idxAra describes exactly 2 pairs of the same idxs, a->b and b->a
std::unordered_map<uint64_t, int> edgeCount;
std::unordered_map<uint64_t, int> altEdgeCount;
scene::DrawableMeshTopology meshTopology =
scene::DrawableMeshTopology::ClosedManifold;
for (uint32_t idx = 0; idx < numIdxs; idx += 3) {
uint64_t vals[] = {uint64_t(idxAra[idx]), uint64_t(idxAra[idx + 1]),
uint64_t(idxAra[idx + 2])};
uint64_t shift_vals[] = {vals[0] << 32, vals[1] << 32, vals[2] << 32};
// for each edge in poly
for (uint32_t i = 0; i < 3; ++i) {
uint32_t next_i = (i + 1) % 3;
auto res =
edgeCount.emplace(std::make_pair(shift_vals[i] + vals[next_i], 0));
if (!res.second) {
res.first->second += 1;
// Duplicate edge with same orientation
meshTopology = scene::DrawableMeshTopology::NonManifold;
}
// Alt edge placement - verify the alternate edge is present
altEdgeCount.emplace(std::make_pair(shift_vals[next_i] + vals[i], 0));
}
}
// If still closed manifold then check that every edge has an alt edge
// present
if (meshTopology == scene::DrawableMeshTopology::ClosedManifold) {
for (const auto entry : edgeCount) {
altEdgeCount.erase(entry.first);
}
if (altEdgeCount.size() > 0) {
meshTopology = scene::DrawableMeshTopology::OpenManifold;
}
}

// locate the scene node which contains the current drawable
scene::SceneNode& node = staticDrawableInfo[iEntry].node;
// Surface area of the mesh : .5 * ba.cross(bc)
double ttlSurfaceArea = 0.0;

// Volume of the mesh : 1/6 * (OA.dot(ba.cross(bc)))
// Where O is a distant vertex
// Only applicable on closed manifold meshes (i.e. all edges have exactly
// 2 faces)
double ttlVolume = 0.0f;

// locate the scene node which contains the current drawable
scene::SceneNode& node = staticDrawableInfo[iEntry].node;
// # of indices
int numIdxs = meshData->indexCount();

// const auto idxView = meshData->indices<std::uint32_t>();
const auto idxView = meshData->indicesAsArray();
Mn::Vector3 distPt{1000, 1000, 1000};
for (uint32_t rawIdx = 0; rawIdx < numIdxs; rawIdx += 3) {
const auto aVert = posArray[idxView[rawIdx + 1]];
Mn::Vector3 a = posArray[idxView[rawIdx]] - aVert;
Mn::Vector3 b = posArray[idxView[rawIdx + 2]] - aVert;
Mn::Vector3 areaNorm = 0.5 * Mn::Math::cross(a, b);
double surfArea = areaNorm.length();
ttlSurfaceArea += surfArea;
Mn::Vector3 c = distPt - aVert;
double signedVol = (Mn::Math::dot(c, areaNorm)) / 3.0;
ttlVolume += signedVol;
if (meshTopology == scene::DrawableMeshTopology::ClosedManifold) {
Mn::Vector3 origin{};
for (uint32_t idx = 0; idx < numIdxs; idx += 3) {
const auto aVert = posArray[idxAra[idx + 1]];
Mn::Vector3 aVec = posArray[idxAra[idx]] - aVert;
Mn::Vector3 bVec = posArray[idxAra[idx + 2]] - aVert;
Mn::Vector3 areaNormVec = 0.5 * Mn::Math::cross(aVec, bVec);
double surfArea = areaNormVec.length();
ttlSurfaceArea += surfArea;
Mn::Vector3 c = origin - aVert;
double signedVol = (Mn::Math::dot(c, areaNormVec)) / 3.0;
ttlVolume += signedVol;
}
} else {
// Open or non-manifold meshes won't have an accurate volume calc
for (uint32_t idx = 0; idx < numIdxs; idx += 3) {
const auto aVert = posArray[idxAra[idx + 1]];
Mn::Vector3 aVec = posArray[idxAra[idx]] - aVert;
Mn::Vector3 bVec = posArray[idxAra[idx + 2]] - aVert;
Mn::Vector3 areaNormVec = 0.5 * Mn::Math::cross(aVec, bVec);
double surfArea = areaNormVec.length();
ttlSurfaceArea += surfArea;
}
}

// set the node's volume and surface area
node.setMeshVolume(ttlVolume);
node.setMeshSurfaceArea(ttlSurfaceArea);

// Set whether the mesh is manifold and/or closed/watertight
node.setMeshTopology(meshTopology);
} // iEntry

} // ResourceManager::computeGeneralMeshVolume
Expand Down Expand Up @@ -3196,9 +3245,9 @@ void ResourceManager::addComponent(
drawableConfig); // instance skinning data

// compute the bounding box for the mesh we are adding
if (computeAbsoluteAABBs) {
staticDrawableInfo.emplace_back(StaticDrawableInfo{node, meshID});
}
// if (computeAbsoluteAABBs) {
staticDrawableInfo.emplace_back(StaticDrawableInfo{node, meshID});
//}
BaseMesh* meshBB = meshes_.at(meshID).get();
node.setMeshBB(computeMeshBB(meshBB));
}
Expand Down
22 changes: 20 additions & 2 deletions src/esp/scene/SceneNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ enum class SceneNodeType {
OBJECT = 4, // objects added via physics api
};

// Topological nature of the drawable mesh held by this scene node, if exists
enum class DrawableMeshTopology {
Unknown = ID_UNDEFINED,
ClosedManifold = 0,
NonManifold,
OpenManifold

};

/**
* @brief This enum holds the idx values for the vector of various types
* of IDs that can be rendered via semantic sensors.
Expand Down Expand Up @@ -293,6 +302,11 @@ class SceneNode : public MagnumObject,
//! set frustum plane in last frame that culls this node
void setFrustumPlaneIndex(int index) { frustumPlaneIndex = index; };

DrawableMeshTopology getMeshTopology() const { return isClosedManifold_; }

void setMeshTopology(DrawableMeshTopology _isClosedManifold) {
isClosedManifold_ = _isClosedManifold;
}
//! Set this node's drawable's volume
void setMeshVolume(double _volume) { volume_ = _volume; }
//! Get this node's drawable's volume
Expand Down Expand Up @@ -341,11 +355,15 @@ class SceneNode : public MagnumObject,
//! The absolute translation of this node, updated in clean
Magnum::Matrix4 absoluteTransformation_;

//! Whether the drawable mesh is closed and manifold (ever edge is adjacent to
//! exactly 2 faces)
DrawableMeshTopology isClosedManifold_ = DrawableMeshTopology::Unknown;

//! The volume of the drawable mesh held in this node
double volume_ = 0.0f;
double volume_ = 0.0;

//! The surface area of the drawable mesh held in this node
double surfArea_ = 0.0f;
double surfArea_ = 0.0;

//! the global bounding box for *static* meshes stored at this node
// NOTE: this is different from the local bounding box meshBB_ defined above:
Expand Down

0 comments on commit fc9edba

Please sign in to comment.