Add skeleton to mesh generation(finished one side)
parent
d3e82ea306
commit
14bce78a4a
|
@ -0,0 +1 @@
|
|||
moc_*
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue