Add skeleton to mesh generation(finished one side)

master
Jeremy Hu 2018-03-12 13:27:22 +08:00
parent d3e82ea306
commit 14bce78a4a
10 changed files with 165 additions and 23 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
moc_*

View File

@ -10,7 +10,9 @@
#include "meshlite.h"
#include "skeletontomesh.h"
MainWindow::MainWindow()
MainWindow::MainWindow() :
m_skeletonToMesh(NULL),
m_skeletonDirty(false)
{
QPushButton *skeletonButton = new QPushButton("Skeleton");
QPushButton *motionButton = new QPushButton("Motion");
@ -94,21 +96,29 @@ MainWindow::MainWindow()
void MainWindow::meshReady()
{
SkeletonToMesh *worker = dynamic_cast<SkeletonToMesh *>(sender());
if (worker) {
m_modelingWidget->updateMesh(worker->takeResultMesh());
m_modelingWidget->updateMesh(m_skeletonToMesh->takeResultMesh());
delete m_skeletonToMesh;
m_skeletonToMesh = NULL;
if (m_skeletonDirty) {
skeletonChanged();
}
}
void MainWindow::skeletonChanged()
{
if (m_skeletonToMesh) {
m_skeletonDirty = true;
return;
}
m_skeletonDirty = false;
QThread *thread = new QThread;
SkeletonToMesh *worker = new SkeletonToMesh(m_skeletonEditWidget->graphicsView());
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), this, SLOT(meshReady()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
m_skeletonToMesh = new SkeletonToMesh(m_skeletonEditWidget->graphicsView());
m_skeletonToMesh->moveToThread(thread);
connect(thread, SIGNAL(started()), m_skeletonToMesh, SLOT(process()));
connect(m_skeletonToMesh, SIGNAL(finished()), this, SLOT(meshReady()));
connect(m_skeletonToMesh, SIGNAL(finished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}

View File

@ -3,6 +3,7 @@
#include <QMainWindow>
#include "modelingwidget.h"
#include "skeletoneditwidget.h"
#include "skeletontomesh.h"
class MainWindow : public QMainWindow
{
@ -15,6 +16,8 @@ public slots:
private:
ModelingWidget *m_modelingWidget;
SkeletonEditWidget *m_skeletonEditWidget;
SkeletonToMesh *m_skeletonToMesh;
bool m_skeletonDirty;
};
#endif

View File

@ -6,6 +6,7 @@ SkeletonEditEdgeItem::SkeletonEditEdgeItem(QGraphicsItem *parent) :
m_firstNode(NULL),
m_secondNode(NULL)
{
setData(0, "edge");
QPen pen(Qt::darkGray);
pen.setWidth(15);
setPen(pen);
@ -25,3 +26,13 @@ void SkeletonEditEdgeItem::updatePosition()
setLine(line);
}
}
SkeletonEditNodeItem *SkeletonEditEdgeItem::firstNode()
{
return m_firstNode;
}
SkeletonEditNodeItem *SkeletonEditEdgeItem::secondNode()
{
return m_secondNode;
}

View File

@ -9,6 +9,8 @@ public:
SkeletonEditEdgeItem(QGraphicsItem *parent = 0);
void setNodes(SkeletonEditNodeItem *first, SkeletonEditNodeItem *second);
void updatePosition();
SkeletonEditNodeItem *firstNode();
SkeletonEditNodeItem *secondNode();
private:
SkeletonEditNodeItem *m_firstNode;
SkeletonEditNodeItem *m_secondNode;

View File

@ -61,9 +61,8 @@ SkeletonEditNodeItem *SkeletonEditGraphicsView::findNodeItemByPos(QPointF pos)
QList<QGraphicsItem *>::iterator it;
QList<QGraphicsItem *> list = scene()->items();
for (it = list.begin(); it != list.end(); ++it) {
SkeletonEditNodeItem *nodeItem = dynamic_cast<SkeletonEditNodeItem *>(*it);
if (nodeItem) {
SkeletonEditNodeItem *nodeItem = (SkeletonEditNodeItem *)(*it);
if ((*it)->data(0).toString() == "node") {
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
if (nodeItem->rect().contains(pos)) {
return nodeItem;
}

View File

@ -6,6 +6,7 @@ SkeletonEditNodeItem::SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *pa
m_highlighted(false),
m_isNextStartNode(false)
{
setData(0, "node");
updateBorder();
}
@ -15,6 +16,11 @@ QPointF SkeletonEditNodeItem::origin()
rect().top() + rect().height() / 2);
}
float SkeletonEditNodeItem::radius()
{
return rect().width() / 2;
}
void SkeletonEditNodeItem::setHighlighted(bool highlighted)
{
m_highlighted = highlighted;

View File

@ -7,6 +7,7 @@ class SkeletonEditNodeItem : public QGraphicsEllipseItem
public:
SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *parent = 0);
QPointF origin();
float radius();
void setHighlighted(bool highlited);
void setIsNextStartNode(bool isNextStartNode);
private:

View File

@ -1,11 +1,63 @@
#include "skeletontomesh.h"
#include "meshlite.h"
#include "skeletoneditnodeitem.h"
#include "skeletoneditedgeitem.h"
// Modified from https://wiki.qt.io/QThreads_general_usage
SkeletonToMesh::SkeletonToMesh(SkeletonEditGraphicsView *graphicsView) :
m_mesh(NULL)
struct NodeItemInfo
{
int index;
int neighborCount;
};
SkeletonToMesh::SkeletonToMesh(SkeletonEditGraphicsView *graphicsView) :
m_mesh(NULL), m_rootNodeId(0)
{
QList<QGraphicsItem *>::iterator it;
QList<QGraphicsItem *> list = graphicsView->scene()->items();
std::map<SkeletonEditNodeItem *, NodeItemInfo> nodeItemsMap;
int maxNeighborCount = 0;
for (it = list.begin(); it != list.end(); ++it) {
if ((*it)->data(0).toString() == "edge") {
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
SkeletonEditNodeItem *nodeItems[] = {edgeItem->firstNode(), edgeItem->secondNode()};
int nodeIndices[] = {0, 0};
for (int i = 0; i < 2; i++) {
SkeletonEditNodeItem *nodeItem = nodeItems[i];
std::map<SkeletonEditNodeItem *, NodeItemInfo>::iterator findResult = nodeItemsMap.find(nodeItem);
if (findResult == nodeItemsMap.end()) {
SkeletonNode node;
NodeItemInfo info;
QPointF origin = nodeItem->origin();
node.originX = origin.x();
node.originY = origin.y();
node.originZ = 0;
node.bmeshNodeId = -1;
node.radius = nodeItem->radius();
info.index = m_nodes.size();
info.neighborCount = 1;
nodeIndices[i] = info.index;
nodeItemsMap[nodeItem] = info;
m_nodes.push_back(node);
} else {
nodeIndices[i] = findResult->second.index;
findResult->second.neighborCount++;
if (findResult->second.neighborCount > maxNeighborCount) {
m_rootNodeId = findResult->second.index;
maxNeighborCount = findResult->second.neighborCount;
}
}
}
SkeletonEdge edge;
edge.firstNode = nodeIndices[0];
edge.secondNode = nodeIndices[1];
m_edges.push_back(edge);
}
}
}
SkeletonToMesh::~SkeletonToMesh()
@ -22,13 +74,50 @@ Mesh *SkeletonToMesh::takeResultMesh()
void SkeletonToMesh::process()
{
void *lite = meshlite_create_context();
int first = meshlite_import(lite, "../assets/cube.obj");
int second = meshlite_import(lite, "../assets/ball.obj");
meshlite_scale(lite, first, 0.65);
int merged = meshlite_union(lite, first, second);
int triangulate = meshlite_triangulate(lite, merged);
//meshlite_export(lite, triangulate, "/Users/jeremy/testlib.obj");
m_mesh = new Mesh(lite, triangulate);
if (m_nodes.size() <= 1) {
emit finished();
return;
}
float left = -1;
float top = -1;
float bottom = -1;
for (size_t i = 0; i < m_nodes.size(); i++) {
SkeletonNode *node = &m_nodes[i];
if (left < 0 || node->originX < left) {
left = node->originX;
}
if (top < 0 || node->originY < top) {
top = node->originY;
}
if (node->originY > bottom) {
bottom = node->originY;
}
}
float height = bottom - top;
if (height <= 0) {
emit finished();
return;
}
void *context = meshlite_create_context();
int bmesh = meshlite_bmesh_create(context);
for (size_t i = 0; i < m_nodes.size(); i++) {
SkeletonNode *node = &m_nodes[i];
float x = (node->originX - left) / height;
float y = (node->originY - top) / height;
float z = node->originZ / height;
float r = node->radius / height;
node->bmeshNodeId = meshlite_bmesh_add_node(context, bmesh, x, y, z, r);
}
for (size_t i = 0; i < m_edges.size(); i++) {
SkeletonNode *firstNode = &m_nodes[m_edges[i].firstNode];
SkeletonNode *secondNode = &m_nodes[m_edges[i].secondNode];
meshlite_bmesh_add_edge(context, bmesh, firstNode->bmeshNodeId, secondNode->bmeshNodeId);
}
int mesh = meshlite_bmesh_generate_mesh(context, bmesh, m_nodes[m_rootNodeId].bmeshNodeId);
meshlite_bmesh_destroy(context, bmesh);
int triangulate = meshlite_triangulate(context, mesh);
meshlite_export(context, triangulate, "/Users/jeremy/testlib.obj");
m_mesh = new Mesh(context, triangulate);
meshlite_destroy_context(context);
emit finished();
}

View File

@ -2,9 +2,26 @@
#define SKELETON_TO_MESH_H
#include <QObject>
#include <QList>
#include <vector>
#include <map>
#include "skeletoneditgraphicsview.h"
#include "mesh.h"
struct SkeletonNode
{
float originX;
float originY;
float originZ;
float radius;
int bmeshNodeId;
};
struct SkeletonEdge
{
int firstNode;
int secondNode;
};
class SkeletonToMesh : public QObject
{
Q_OBJECT
@ -18,6 +35,9 @@ public slots:
void process();
private:
Mesh *m_mesh;
std::vector<SkeletonNode> m_nodes;
std::vector<SkeletonEdge> m_edges;
int m_rootNodeId;
};
#endif