Improve mesh generation

Insert intermediate nodes automatically between nodes of long edges to avoid generating tiny area but long edge triangles.
master
Jeremy Hu 2018-11-12 07:21:34 +08:00
parent 39cfe6537d
commit 1f8f7913a7
1 changed files with 85 additions and 25 deletions

View File

@ -279,6 +279,14 @@ void *MeshGenerator::combinePartMesh(QString partId)
cacheBmeshVertices.clear(); cacheBmeshVertices.clear();
cacheBmeshQuads.clear(); cacheBmeshQuads.clear();
std::map<int, std::vector<int>> bmeshNodeIdToDataMap; std::map<int, std::vector<int>> bmeshNodeIdToDataMap;
struct NodeInfo
{
float radius = 0;
QVector3D position;
BoneMark boneMark = BoneMark::None;
};
std::map<QString, NodeInfo> nodeInfos;
for (const auto &nodeId: m_partNodeIds[partId]) { for (const auto &nodeId: m_partNodeIds[partId]) {
auto findNode = m_snapshot->nodes.find(nodeId); auto findNode = m_snapshot->nodes.find(nodeId);
if (findNode == m_snapshot->nodes.end()) { if (findNode == m_snapshot->nodes.end()) {
@ -291,34 +299,15 @@ void *MeshGenerator::combinePartMesh(QString partId)
float x = (valueOfKeyInMapOrEmpty(node, "x").toFloat() - m_mainProfileMiddleX); float x = (valueOfKeyInMapOrEmpty(node, "x").toFloat() - m_mainProfileMiddleX);
float y = (m_mainProfileMiddleY - valueOfKeyInMapOrEmpty(node, "y").toFloat()); float y = (m_mainProfileMiddleY - valueOfKeyInMapOrEmpty(node, "y").toFloat());
float z = (m_sideProfileMiddleX - valueOfKeyInMapOrEmpty(node, "z").toFloat()); float z = (m_sideProfileMiddleX - valueOfKeyInMapOrEmpty(node, "z").toFloat());
int bmeshNodeId = meshlite_bmesh_add_node(m_meshliteContext, bmeshId, x, y, z, radius);
BoneMark boneMark = BoneMarkFromString(valueOfKeyInMapOrEmpty(node, "boneMark").toUtf8().constData()); BoneMark boneMark = BoneMarkFromString(valueOfKeyInMapOrEmpty(node, "boneMark").toUtf8().constData());
nodeToBmeshIdMap[nodeId] = bmeshNodeId; auto &nodeInfo = nodeInfos[nodeId];
bmeshToNodeIdMap[bmeshNodeId] = nodeId; nodeInfo.position = QVector3D(x, y, z);
nodeInfo.radius = radius;
OutcomeNode bmeshNode; nodeInfo.boneMark = boneMark;
bmeshNode.partId = QUuid(partId);
bmeshNode.origin = QVector3D(x, y, z);
bmeshNode.radius = radius;
bmeshNode.nodeId = QUuid(nodeId);
bmeshNode.color = partColor;
bmeshNode.materialId = materialId;
bmeshNode.boneMark = boneMark;
bmeshNode.mirroredByPartId = mirroredPartId;
bmeshNodeIdToDataMap[bmeshNodeId].push_back(cacheBmeshNodes.size());
cacheBmeshNodes.push_back(bmeshNode);
if (xMirrored) {
bmeshNode.partId = mirroredPartId;
bmeshNode.mirrorFromPartId = QUuid(partId);
bmeshNode.mirroredByPartId = QUuid();
bmeshNode.origin.setX(-x);
bmeshNodeIdToDataMap[bmeshNodeId].push_back(cacheBmeshNodes.size());
cacheBmeshNodes.push_back(bmeshNode);
} }
} std::set<std::pair<QString, QString>> edges;
for (const auto &edgeId: m_partEdgeIds[partId]) { for (const auto &edgeId: m_partEdgeIds[partId]) {
auto findEdge = m_snapshot->edges.find(edgeId); auto findEdge = m_snapshot->edges.find(edgeId);
if (findEdge == m_snapshot->edges.end()) { if (findEdge == m_snapshot->edges.end()) {
@ -330,6 +319,77 @@ void *MeshGenerator::combinePartMesh(QString partId)
QString fromNodeId = valueOfKeyInMapOrEmpty(edge, "from"); QString fromNodeId = valueOfKeyInMapOrEmpty(edge, "from");
QString toNodeId = valueOfKeyInMapOrEmpty(edge, "to"); QString toNodeId = valueOfKeyInMapOrEmpty(edge, "to");
std::function<void(const QString &, const QString &)> connectNodes;
connectNodes = [&connectNodes, &edges, &nodeInfos](const QString &fromNodeId, const QString &toNodeId) {
const auto &findFromNodeInfo = nodeInfos.find(fromNodeId);
if (findFromNodeInfo == nodeInfos.end()) {
qDebug() << "Find from-node info failed:" << fromNodeId;
return;
}
const auto &findToNodeInfo = nodeInfos.find(toNodeId);
if (findToNodeInfo == nodeInfos.end()) {
qDebug() << "Find to-node info failed:" << toNodeId;
return;
}
auto distanceBetweenNodes = findFromNodeInfo->second.position.distanceToPoint(findToNodeInfo->second.position);
float centerEmptyLength = distanceBetweenNodes - (findFromNodeInfo->second.radius + findToNodeInfo->second.radius);
if (centerEmptyLength < distanceBetweenNodes * 0.5) {
edges.insert({fromNodeId, toNodeId});
return;
}
// Cut off by add intermediate nodes
QString newNodeId = QUuid::createUuid().toString();
auto &nodeInfo = nodeInfos[newNodeId];
nodeInfo.position = (findFromNodeInfo->second.position + findToNodeInfo->second.position) / 2;
nodeInfo.radius = (findFromNodeInfo->second.radius + findToNodeInfo->second.radius) / 2;
connectNodes(fromNodeId, newNodeId);
connectNodes(newNodeId, toNodeId);
};
connectNodes(fromNodeId, toNodeId);
}
for (const auto &nodeIt: nodeInfos) {
const auto &nodeId = nodeIt.first;
const auto &nodeInfo = nodeIt.second;
int bmeshNodeId = meshlite_bmesh_add_node(m_meshliteContext, bmeshId,
nodeInfo.position.x(), nodeInfo.position.y(), nodeInfo.position.z(), nodeInfo.radius);
nodeToBmeshIdMap[nodeId] = bmeshNodeId;
bmeshToNodeIdMap[bmeshNodeId] = nodeId;
OutcomeNode bmeshNode;
bmeshNode.partId = QUuid(partId);
bmeshNode.origin = nodeInfo.position;
bmeshNode.radius = nodeInfo.radius;
bmeshNode.nodeId = QUuid(nodeId);
bmeshNode.color = partColor;
bmeshNode.materialId = materialId;
bmeshNode.boneMark = nodeInfo.boneMark;
bmeshNode.mirroredByPartId = mirroredPartId;
bmeshNodeIdToDataMap[bmeshNodeId].push_back(cacheBmeshNodes.size());
cacheBmeshNodes.push_back(bmeshNode);
if (xMirrored) {
bmeshNode.partId = mirroredPartId;
bmeshNode.mirrorFromPartId = QUuid(partId);
bmeshNode.mirroredByPartId = QUuid();
bmeshNode.origin.setX(-nodeInfo.position.x());
bmeshNodeIdToDataMap[bmeshNodeId].push_back(cacheBmeshNodes.size());
cacheBmeshNodes.push_back(bmeshNode);
}
}
for (const auto &edgeIt: edges) {
const QString &fromNodeId = edgeIt.first;
const QString &toNodeId = edgeIt.second;
auto findFromBmeshId = nodeToBmeshIdMap.find(fromNodeId); auto findFromBmeshId = nodeToBmeshIdMap.find(fromNodeId);
if (findFromBmeshId == nodeToBmeshIdMap.end()) { if (findFromBmeshId == nodeToBmeshIdMap.end()) {
qDebug() << "Find from-node bmesh failed:" << fromNodeId; qDebug() << "Find from-node bmesh failed:" << fromNodeId;