Add skeleton to mesh generation(finished one side)
parent
d3e82ea306
commit
14bce78a4a
|
@ -0,0 +1 @@
|
||||||
|
moc_*
|
|
@ -10,7 +10,9 @@
|
||||||
#include "meshlite.h"
|
#include "meshlite.h"
|
||||||
#include "skeletontomesh.h"
|
#include "skeletontomesh.h"
|
||||||
|
|
||||||
MainWindow::MainWindow()
|
MainWindow::MainWindow() :
|
||||||
|
m_skeletonToMesh(NULL),
|
||||||
|
m_skeletonDirty(false)
|
||||||
{
|
{
|
||||||
QPushButton *skeletonButton = new QPushButton("Skeleton");
|
QPushButton *skeletonButton = new QPushButton("Skeleton");
|
||||||
QPushButton *motionButton = new QPushButton("Motion");
|
QPushButton *motionButton = new QPushButton("Motion");
|
||||||
|
@ -94,21 +96,29 @@ MainWindow::MainWindow()
|
||||||
|
|
||||||
void MainWindow::meshReady()
|
void MainWindow::meshReady()
|
||||||
{
|
{
|
||||||
SkeletonToMesh *worker = dynamic_cast<SkeletonToMesh *>(sender());
|
m_modelingWidget->updateMesh(m_skeletonToMesh->takeResultMesh());
|
||||||
if (worker) {
|
delete m_skeletonToMesh;
|
||||||
m_modelingWidget->updateMesh(worker->takeResultMesh());
|
m_skeletonToMesh = NULL;
|
||||||
|
if (m_skeletonDirty) {
|
||||||
|
skeletonChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::skeletonChanged()
|
void MainWindow::skeletonChanged()
|
||||||
{
|
{
|
||||||
|
if (m_skeletonToMesh) {
|
||||||
|
m_skeletonDirty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_skeletonDirty = false;
|
||||||
|
|
||||||
QThread *thread = new QThread;
|
QThread *thread = new QThread;
|
||||||
SkeletonToMesh *worker = new SkeletonToMesh(m_skeletonEditWidget->graphicsView());
|
m_skeletonToMesh = new SkeletonToMesh(m_skeletonEditWidget->graphicsView());
|
||||||
worker->moveToThread(thread);
|
m_skeletonToMesh->moveToThread(thread);
|
||||||
connect(thread, SIGNAL(started()), worker, SLOT(process()));
|
connect(thread, SIGNAL(started()), m_skeletonToMesh, SLOT(process()));
|
||||||
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
|
connect(m_skeletonToMesh, SIGNAL(finished()), this, SLOT(meshReady()));
|
||||||
connect(worker, SIGNAL(finished()), this, SLOT(meshReady()));
|
connect(m_skeletonToMesh, SIGNAL(finished()), thread, SLOT(quit()));
|
||||||
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
|
|
||||||
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||||
thread->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include "modelingwidget.h"
|
#include "modelingwidget.h"
|
||||||
#include "skeletoneditwidget.h"
|
#include "skeletoneditwidget.h"
|
||||||
|
#include "skeletontomesh.h"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
|
@ -15,6 +16,8 @@ public slots:
|
||||||
private:
|
private:
|
||||||
ModelingWidget *m_modelingWidget;
|
ModelingWidget *m_modelingWidget;
|
||||||
SkeletonEditWidget *m_skeletonEditWidget;
|
SkeletonEditWidget *m_skeletonEditWidget;
|
||||||
|
SkeletonToMesh *m_skeletonToMesh;
|
||||||
|
bool m_skeletonDirty;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,7 @@ SkeletonEditEdgeItem::SkeletonEditEdgeItem(QGraphicsItem *parent) :
|
||||||
m_firstNode(NULL),
|
m_firstNode(NULL),
|
||||||
m_secondNode(NULL)
|
m_secondNode(NULL)
|
||||||
{
|
{
|
||||||
|
setData(0, "edge");
|
||||||
QPen pen(Qt::darkGray);
|
QPen pen(Qt::darkGray);
|
||||||
pen.setWidth(15);
|
pen.setWidth(15);
|
||||||
setPen(pen);
|
setPen(pen);
|
||||||
|
@ -25,3 +26,13 @@ void SkeletonEditEdgeItem::updatePosition()
|
||||||
setLine(line);
|
setLine(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SkeletonEditNodeItem *SkeletonEditEdgeItem::firstNode()
|
||||||
|
{
|
||||||
|
return m_firstNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkeletonEditNodeItem *SkeletonEditEdgeItem::secondNode()
|
||||||
|
{
|
||||||
|
return m_secondNode;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ public:
|
||||||
SkeletonEditEdgeItem(QGraphicsItem *parent = 0);
|
SkeletonEditEdgeItem(QGraphicsItem *parent = 0);
|
||||||
void setNodes(SkeletonEditNodeItem *first, SkeletonEditNodeItem *second);
|
void setNodes(SkeletonEditNodeItem *first, SkeletonEditNodeItem *second);
|
||||||
void updatePosition();
|
void updatePosition();
|
||||||
|
SkeletonEditNodeItem *firstNode();
|
||||||
|
SkeletonEditNodeItem *secondNode();
|
||||||
private:
|
private:
|
||||||
SkeletonEditNodeItem *m_firstNode;
|
SkeletonEditNodeItem *m_firstNode;
|
||||||
SkeletonEditNodeItem *m_secondNode;
|
SkeletonEditNodeItem *m_secondNode;
|
||||||
|
|
|
@ -61,9 +61,8 @@ SkeletonEditNodeItem *SkeletonEditGraphicsView::findNodeItemByPos(QPointF pos)
|
||||||
QList<QGraphicsItem *>::iterator it;
|
QList<QGraphicsItem *>::iterator it;
|
||||||
QList<QGraphicsItem *> list = scene()->items();
|
QList<QGraphicsItem *> list = scene()->items();
|
||||||
for (it = list.begin(); it != list.end(); ++it) {
|
for (it = list.begin(); it != list.end(); ++it) {
|
||||||
SkeletonEditNodeItem *nodeItem = dynamic_cast<SkeletonEditNodeItem *>(*it);
|
if ((*it)->data(0).toString() == "node") {
|
||||||
if (nodeItem) {
|
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
|
||||||
SkeletonEditNodeItem *nodeItem = (SkeletonEditNodeItem *)(*it);
|
|
||||||
if (nodeItem->rect().contains(pos)) {
|
if (nodeItem->rect().contains(pos)) {
|
||||||
return nodeItem;
|
return nodeItem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ SkeletonEditNodeItem::SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *pa
|
||||||
m_highlighted(false),
|
m_highlighted(false),
|
||||||
m_isNextStartNode(false)
|
m_isNextStartNode(false)
|
||||||
{
|
{
|
||||||
|
setData(0, "node");
|
||||||
updateBorder();
|
updateBorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +16,11 @@ QPointF SkeletonEditNodeItem::origin()
|
||||||
rect().top() + rect().height() / 2);
|
rect().top() + rect().height() / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SkeletonEditNodeItem::radius()
|
||||||
|
{
|
||||||
|
return rect().width() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonEditNodeItem::setHighlighted(bool highlighted)
|
void SkeletonEditNodeItem::setHighlighted(bool highlighted)
|
||||||
{
|
{
|
||||||
m_highlighted = highlighted;
|
m_highlighted = highlighted;
|
||||||
|
|
|
@ -7,6 +7,7 @@ class SkeletonEditNodeItem : public QGraphicsEllipseItem
|
||||||
public:
|
public:
|
||||||
SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *parent = 0);
|
SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *parent = 0);
|
||||||
QPointF origin();
|
QPointF origin();
|
||||||
|
float radius();
|
||||||
void setHighlighted(bool highlited);
|
void setHighlighted(bool highlited);
|
||||||
void setIsNextStartNode(bool isNextStartNode);
|
void setIsNextStartNode(bool isNextStartNode);
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,11 +1,63 @@
|
||||||
#include "skeletontomesh.h"
|
#include "skeletontomesh.h"
|
||||||
#include "meshlite.h"
|
#include "meshlite.h"
|
||||||
|
#include "skeletoneditnodeitem.h"
|
||||||
|
#include "skeletoneditedgeitem.h"
|
||||||
|
|
||||||
// Modified from https://wiki.qt.io/QThreads_general_usage
|
// Modified from https://wiki.qt.io/QThreads_general_usage
|
||||||
|
|
||||||
SkeletonToMesh::SkeletonToMesh(SkeletonEditGraphicsView *graphicsView) :
|
struct NodeItemInfo
|
||||||
m_mesh(NULL)
|
|
||||||
{
|
{
|
||||||
|
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()
|
SkeletonToMesh::~SkeletonToMesh()
|
||||||
|
@ -22,13 +74,50 @@ Mesh *SkeletonToMesh::takeResultMesh()
|
||||||
|
|
||||||
void SkeletonToMesh::process()
|
void SkeletonToMesh::process()
|
||||||
{
|
{
|
||||||
void *lite = meshlite_create_context();
|
if (m_nodes.size() <= 1) {
|
||||||
int first = meshlite_import(lite, "../assets/cube.obj");
|
emit finished();
|
||||||
int second = meshlite_import(lite, "../assets/ball.obj");
|
return;
|
||||||
meshlite_scale(lite, first, 0.65);
|
}
|
||||||
int merged = meshlite_union(lite, first, second);
|
float left = -1;
|
||||||
int triangulate = meshlite_triangulate(lite, merged);
|
float top = -1;
|
||||||
//meshlite_export(lite, triangulate, "/Users/jeremy/testlib.obj");
|
float bottom = -1;
|
||||||
m_mesh = new Mesh(lite, triangulate);
|
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();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,26 @@
|
||||||
#define SKELETON_TO_MESH_H
|
#define SKELETON_TO_MESH_H
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include "skeletoneditgraphicsview.h"
|
#include "skeletoneditgraphicsview.h"
|
||||||
#include "mesh.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
|
class SkeletonToMesh : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +35,9 @@ public slots:
|
||||||
void process();
|
void process();
|
||||||
private:
|
private:
|
||||||
Mesh *m_mesh;
|
Mesh *m_mesh;
|
||||||
|
std::vector<SkeletonNode> m_nodes;
|
||||||
|
std::vector<SkeletonEdge> m_edges;
|
||||||
|
int m_rootNodeId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue