Support new export format: .ds3obj
ds3obj is the abbreviation of Dust3D Object. It include the result mesh, rig, motions and extra informations such as nodes, edges which doesn't include in the glTF and FBX files.master
parent
a8c7f55de2
commit
6c9d908a76
|
@ -260,8 +260,8 @@ HEADERS += src/skeletonside.h
|
||||||
SOURCES += src/meshsplitter.cpp
|
SOURCES += src/meshsplitter.cpp
|
||||||
HEADERS += src/meshsplitter.h
|
HEADERS += src/meshsplitter.h
|
||||||
|
|
||||||
SOURCES += src/rigger.cpp
|
SOURCES += src/rig.cpp
|
||||||
HEADERS += src/rigger.h
|
HEADERS += src/rig.h
|
||||||
|
|
||||||
SOURCES += src/rigtype.cpp
|
SOURCES += src/rigtype.cpp
|
||||||
HEADERS += src/rigtype.h
|
HEADERS += src/rigtype.h
|
||||||
|
@ -526,6 +526,9 @@ HEADERS += src/vertebratamotionparameterswidget.h
|
||||||
SOURCES += src/objectxml.cpp
|
SOURCES += src/objectxml.cpp
|
||||||
HEADERS += src/objectxml.h
|
HEADERS += src/objectxml.h
|
||||||
|
|
||||||
|
SOURCES += src/rigxml.cpp
|
||||||
|
HEADERS += src/rigxml.h
|
||||||
|
|
||||||
SOURCES += src/main.cpp
|
SOURCES += src/main.cpp
|
||||||
|
|
||||||
HEADERS += src/version.h
|
HEADERS += src/version.h
|
||||||
|
|
|
@ -3579,12 +3579,12 @@ void Document::rigReady()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<RiggerBone> *Document::resultRigBones() const
|
const std::vector<RigBone> *Document::resultRigBones() const
|
||||||
{
|
{
|
||||||
return m_resultRigBones;
|
return m_resultRigBones;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<int, RiggerVertexWeights> *Document::resultRigWeights() const
|
const std::map<int, RigVertexWeights> *Document::resultRigWeights() const
|
||||||
{
|
{
|
||||||
return m_resultRigWeights;
|
return m_resultRigWeights;
|
||||||
}
|
}
|
||||||
|
@ -3643,8 +3643,8 @@ void Document::generateMotions()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<RiggerBone> *rigBones = resultRigBones();
|
const std::vector<RigBone> *rigBones = resultRigBones();
|
||||||
const std::map<int, RiggerVertexWeights> *rigWeights = resultRigWeights();
|
const std::map<int, RigVertexWeights> *rigWeights = resultRigWeights();
|
||||||
|
|
||||||
if (nullptr == rigBones || nullptr == rigWeights) {
|
if (nullptr == rigBones || nullptr == rigWeights) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -470,8 +470,8 @@ public:
|
||||||
bool isMeshGenerationSucceed();
|
bool isMeshGenerationSucceed();
|
||||||
Model *takeResultTextureMesh();
|
Model *takeResultTextureMesh();
|
||||||
Model *takeResultRigWeightMesh();
|
Model *takeResultRigWeightMesh();
|
||||||
const std::vector<RiggerBone> *resultRigBones() const;
|
const std::vector<RigBone> *resultRigBones() const;
|
||||||
const std::map<int, RiggerVertexWeights> *resultRigWeights() const;
|
const std::map<int, RigVertexWeights> *resultRigWeights() const;
|
||||||
void updateTurnaround(const QImage &image);
|
void updateTurnaround(const QImage &image);
|
||||||
void updateTextureImage(QImage *image);
|
void updateTextureImage(QImage *image);
|
||||||
void updateTextureNormalImage(QImage *image);
|
void updateTextureNormalImage(QImage *image);
|
||||||
|
@ -684,8 +684,8 @@ private: // need initialize
|
||||||
bool m_smoothNormal;
|
bool m_smoothNormal;
|
||||||
RigGenerator *m_rigGenerator;
|
RigGenerator *m_rigGenerator;
|
||||||
Model *m_resultRigWeightMesh;
|
Model *m_resultRigWeightMesh;
|
||||||
std::vector<RiggerBone> *m_resultRigBones;
|
std::vector<RigBone> *m_resultRigBones;
|
||||||
std::map<int, RiggerVertexWeights> *m_resultRigWeights;
|
std::map<int, RigVertexWeights> *m_resultRigWeights;
|
||||||
bool m_isRigObsolete;
|
bool m_isRigObsolete;
|
||||||
Object *m_riggedObject;
|
Object *m_riggedObject;
|
||||||
bool m_currentRigSucceed;
|
bool m_currentRigSucceed;
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "fileforever.h"
|
#include "fileforever.h"
|
||||||
#include "documentsaver.h"
|
#include "documentsaver.h"
|
||||||
#include "objectxml.h"
|
#include "objectxml.h"
|
||||||
|
#include "rigxml.h"
|
||||||
|
|
||||||
int DocumentWindow::m_autoRecovered = false;
|
int DocumentWindow::m_autoRecovered = false;
|
||||||
|
|
||||||
|
@ -584,6 +585,10 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(m_exportTexturesAction, &QAction::triggered, this, &DocumentWindow::exportTextures, Qt::QueuedConnection);
|
connect(m_exportTexturesAction, &QAction::triggered, this, &DocumentWindow::exportTextures, Qt::QueuedConnection);
|
||||||
m_fileMenu->addAction(m_exportTexturesAction);
|
m_fileMenu->addAction(m_exportTexturesAction);
|
||||||
|
|
||||||
|
m_exportDs3objAction = new QAction(tr("Export DS3OBJ..."), this);
|
||||||
|
connect(m_exportDs3objAction, &QAction::triggered, this, &DocumentWindow::exportDs3objResult, Qt::QueuedConnection);
|
||||||
|
m_fileMenu->addAction(m_exportDs3objAction);
|
||||||
|
|
||||||
m_exportRenderedAsImageAction = new QAction(tr("Export as Image..."), this);
|
m_exportRenderedAsImageAction = new QAction(tr("Export as Image..."), this);
|
||||||
connect(m_exportRenderedAsImageAction, &QAction::triggered, this, &DocumentWindow::exportRenderedResult, Qt::QueuedConnection);
|
connect(m_exportRenderedAsImageAction, &QAction::triggered, this, &DocumentWindow::exportRenderedResult, Qt::QueuedConnection);
|
||||||
m_fileMenu->addAction(m_exportRenderedAsImageAction);
|
m_fileMenu->addAction(m_exportRenderedAsImageAction);
|
||||||
|
@ -605,6 +610,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
m_exportAsGlbAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
m_exportAsGlbAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
||||||
m_exportAsFbxAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
m_exportAsFbxAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
||||||
m_exportTexturesAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
m_exportTexturesAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
||||||
|
m_exportDs3objAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady());
|
||||||
m_exportRenderedAsImageAction->setEnabled(m_graphicsWidget->hasItems());
|
m_exportRenderedAsImageAction->setEnabled(m_graphicsWidget->hasItems());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1871,6 +1877,7 @@ void DocumentWindow::openPathAs(const QString &path, const QString &asName)
|
||||||
for (int i = 0; i < ds3Reader.items().size(); ++i) {
|
for (int i = 0; i < ds3Reader.items().size(); ++i) {
|
||||||
Ds3ReaderItem item = ds3Reader.items().at(i);
|
Ds3ReaderItem item = ds3Reader.items().at(i);
|
||||||
if (item.type == "object") {
|
if (item.type == "object") {
|
||||||
|
if (item.name == "object.xml") {
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
ds3Reader.loadItem(item.name, &data);
|
ds3Reader.loadItem(item.name, &data);
|
||||||
QXmlStreamReader stream(data);
|
QXmlStreamReader stream(data);
|
||||||
|
@ -1880,6 +1887,7 @@ void DocumentWindow::openPathAs(const QString &path, const QString &asName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
|
|
||||||
|
@ -2045,6 +2053,17 @@ void DocumentWindow::exportGlbResult()
|
||||||
exportGlbToFilename(filename);
|
exportGlbToFilename(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentWindow::exportDs3objResult()
|
||||||
|
{
|
||||||
|
QString filename = QFileDialog::getSaveFileName(this, QString(), QString(),
|
||||||
|
tr("Dust3D Object (.ds3obj)"));
|
||||||
|
if (filename.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ensureFileExtension(&filename, ".ds3obj");
|
||||||
|
exportDs3objToFilename(filename);
|
||||||
|
}
|
||||||
|
|
||||||
void DocumentWindow::exportGlbToFilename(const QString &filename)
|
void DocumentWindow::exportGlbToFilename(const QString &filename)
|
||||||
{
|
{
|
||||||
if (!m_document->isExportReady()) {
|
if (!m_document->isExportReady()) {
|
||||||
|
@ -2068,6 +2087,101 @@ void DocumentWindow::exportGlbToFilename(const QString &filename)
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentWindow::exportDs3objToFilename(const QString &filename)
|
||||||
|
{
|
||||||
|
if (!m_document->isExportReady()) {
|
||||||
|
qDebug() << "Export but document is not export ready";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
Ds3FileWriter ds3Writer;
|
||||||
|
|
||||||
|
{
|
||||||
|
QByteArray objectXml;
|
||||||
|
QXmlStreamWriter stream(&objectXml);
|
||||||
|
saveObjectToXmlStream(&m_document->currentPostProcessedObject(), &stream);
|
||||||
|
if (objectXml.size() > 0)
|
||||||
|
ds3Writer.add("object.xml", "object", &objectXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<RigBone> *rigBones = m_document->resultRigBones();
|
||||||
|
const std::map<int, RigVertexWeights> *rigWeights = m_document->resultRigWeights();
|
||||||
|
if (nullptr != rigBones && nullptr != rigWeights) {
|
||||||
|
QByteArray rigXml;
|
||||||
|
QXmlStreamWriter stream(&rigXml);
|
||||||
|
saveRigToXmlStream(&m_document->currentPostProcessedObject(), rigBones, rigWeights, &stream);
|
||||||
|
if (rigXml.size() > 0)
|
||||||
|
ds3Writer.add("rig.xml", "rig", &rigXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QByteArray motionsXml;
|
||||||
|
{
|
||||||
|
QXmlStreamWriter stream(&motionsXml);
|
||||||
|
QXmlStreamWriter *writer = &stream;
|
||||||
|
writer->setAutoFormatting(true);
|
||||||
|
writer->writeStartDocument();
|
||||||
|
writer->writeStartElement("motions");
|
||||||
|
for (const auto &motionIt: m_document->motionMap) {
|
||||||
|
writer->writeStartElement("motion");
|
||||||
|
writer->writeAttribute("name", motionIt.second.name);
|
||||||
|
writer->writeStartElement("frames");
|
||||||
|
for (const auto &it: motionIt.second.jointNodeTrees) {
|
||||||
|
writer->writeStartElement("frame");
|
||||||
|
writer->writeAttribute("duration", QString::number(it.first));
|
||||||
|
writer->writeStartElement("bones");
|
||||||
|
const auto &nodes = it.second.nodes();
|
||||||
|
for (size_t boneIndex = 0; boneIndex < nodes.size(); ++boneIndex) {
|
||||||
|
const auto &node = nodes[boneIndex];
|
||||||
|
writer->writeStartElement("bone");
|
||||||
|
writer->writeAttribute("index", QString::number(boneIndex));
|
||||||
|
QMatrix4x4 translationMatrix;
|
||||||
|
translationMatrix.translate(node.translation);
|
||||||
|
QMatrix4x4 rotationMatrix;
|
||||||
|
rotationMatrix.rotate(node.rotation);
|
||||||
|
QMatrix4x4 matrix = translationMatrix * rotationMatrix;
|
||||||
|
const float *floatArray = matrix.constData();
|
||||||
|
QStringList matrixItemList;
|
||||||
|
for (auto j = 0u; j < 16; j++) {
|
||||||
|
matrixItemList += QString::number(floatArray[j]);
|
||||||
|
}
|
||||||
|
writer->writeAttribute("matrix", matrixItemList.join(","));
|
||||||
|
writer->writeEndElement();
|
||||||
|
}
|
||||||
|
writer->writeEndElement();
|
||||||
|
writer->writeEndElement();
|
||||||
|
}
|
||||||
|
writer->writeEndElement();
|
||||||
|
writer->writeEndElement();
|
||||||
|
}
|
||||||
|
writer->writeEndElement();
|
||||||
|
writer->writeEndDocument();
|
||||||
|
}
|
||||||
|
if (motionsXml.size() > 0)
|
||||||
|
ds3Writer.add("motions.xml", "motions", &motionsXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto saveTexture = [&](const QString &filename, const QImage *image) {
|
||||||
|
if (nullptr == image)
|
||||||
|
return;
|
||||||
|
QByteArray byteArray;
|
||||||
|
QBuffer pngBuffer(&byteArray);
|
||||||
|
pngBuffer.open(QIODevice::WriteOnly);
|
||||||
|
image->save(&pngBuffer, "PNG");
|
||||||
|
ds3Writer.add(filename, "asset", &byteArray);
|
||||||
|
};
|
||||||
|
|
||||||
|
saveTexture("object_color.png", m_document->textureImage);
|
||||||
|
saveTexture("object_normal.png", m_document->textureNormalImage);
|
||||||
|
saveTexture("object_metallic.png", m_document->textureMetalnessImage);
|
||||||
|
saveTexture("object_roughness.png", m_document->textureRoughnessImage);
|
||||||
|
saveTexture("object_ao.png", m_document->textureAmbientOcclusionImage);
|
||||||
|
|
||||||
|
ds3Writer.save(filename);
|
||||||
|
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
void DocumentWindow::updateXlockButtonState()
|
void DocumentWindow::updateXlockButtonState()
|
||||||
{
|
{
|
||||||
if (m_document->xlocked)
|
if (m_document->xlocked)
|
||||||
|
|
|
@ -61,6 +61,7 @@ public slots:
|
||||||
void exportGlbResult();
|
void exportGlbResult();
|
||||||
void exportFbxResult();
|
void exportFbxResult();
|
||||||
void exportTextures();
|
void exportTextures();
|
||||||
|
void exportDs3objResult();
|
||||||
void newWindow();
|
void newWindow();
|
||||||
void newDocument();
|
void newDocument();
|
||||||
void saveAs();
|
void saveAs();
|
||||||
|
@ -92,6 +93,7 @@ public slots:
|
||||||
void exportFbxToFilename(const QString &filename);
|
void exportFbxToFilename(const QString &filename);
|
||||||
void exportGlbToFilename(const QString &filename);
|
void exportGlbToFilename(const QString &filename);
|
||||||
void exportTexturesToDirectory(const QString &directory);
|
void exportTexturesToDirectory(const QString &directory);
|
||||||
|
void exportDs3objToFilename(const QString &filename);
|
||||||
void toggleRotation();
|
void toggleRotation();
|
||||||
//void updateInfoWidgetPosition();
|
//void updateInfoWidgetPosition();
|
||||||
void generateNormalAndDepthMaps();
|
void generateNormalAndDepthMaps();
|
||||||
|
@ -146,6 +148,7 @@ private:
|
||||||
QAction *m_exportAsGlbAction;
|
QAction *m_exportAsGlbAction;
|
||||||
QAction *m_exportAsFbxAction;
|
QAction *m_exportAsFbxAction;
|
||||||
QAction *m_exportTexturesAction;
|
QAction *m_exportTexturesAction;
|
||||||
|
QAction *m_exportDs3objAction;
|
||||||
QAction *m_exportRenderedAsImageAction;
|
QAction *m_exportRenderedAsImageAction;
|
||||||
|
|
||||||
QMenu *m_editMenu;
|
QMenu *m_editMenu;
|
||||||
|
|
|
@ -2201,8 +2201,8 @@ void FbxFileWriter::createDefinitions(size_t deformerCount,
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxFileWriter::FbxFileWriter(Object &object,
|
FbxFileWriter::FbxFileWriter(Object &object,
|
||||||
const std::vector<RiggerBone> *resultRigBones,
|
const std::vector<RigBone> *resultRigBones,
|
||||||
const std::map<int, RiggerVertexWeights> *resultRigWeights,
|
const std::map<int, RigVertexWeights> *resultRigWeights,
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
QImage *textureImage,
|
QImage *textureImage,
|
||||||
QImage *normalImage,
|
QImage *normalImage,
|
||||||
|
@ -2415,7 +2415,7 @@ FbxFileWriter::FbxFileWriter(Object &object,
|
||||||
std::vector<std::pair<std::vector<int32_t>, std::vector<double>>> bindPerBone(resultRigBones->size());
|
std::vector<std::pair<std::vector<int32_t>, std::vector<double>>> bindPerBone(resultRigBones->size());
|
||||||
if (resultRigWeights && !resultRigWeights->empty()) {
|
if (resultRigWeights && !resultRigWeights->empty()) {
|
||||||
for (const auto &item: *resultRigWeights) {
|
for (const auto &item: *resultRigWeights) {
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < MAX_WEIGHT_NUM; ++i) {
|
||||||
const auto &boneIndex = item.second.boneIndices[i];
|
const auto &boneIndex = item.second.boneIndices[i];
|
||||||
Q_ASSERT(boneIndex < bindPerBone.size());
|
Q_ASSERT(boneIndex < bindPerBone.size());
|
||||||
if (0 == boneIndex)
|
if (0 == boneIndex)
|
||||||
|
|
|
@ -14,8 +14,8 @@ class FbxFileWriter : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FbxFileWriter(Object &object,
|
FbxFileWriter(Object &object,
|
||||||
const std::vector<RiggerBone> *resultRigBones,
|
const std::vector<RigBone> *resultRigBones,
|
||||||
const std::map<int, RiggerVertexWeights> *resultRigWeights,
|
const std::map<int, RigVertexWeights> *resultRigWeights,
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
QImage *textureImage=nullptr,
|
QImage *textureImage=nullptr,
|
||||||
QImage *normalImage=nullptr,
|
QImage *normalImage=nullptr,
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
bool GlbFileWriter::m_enableComment = false;
|
bool GlbFileWriter::m_enableComment = false;
|
||||||
|
|
||||||
GlbFileWriter::GlbFileWriter(Object &object,
|
GlbFileWriter::GlbFileWriter(Object &object,
|
||||||
const std::vector<RiggerBone> *resultRigBones,
|
const std::vector<RigBone> *resultRigBones,
|
||||||
const std::map<int, RiggerVertexWeights> *resultRigWeights,
|
const std::map<int, RigVertexWeights> *resultRigWeights,
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
QImage *textureImage,
|
QImage *textureImage,
|
||||||
QImage *normalImage,
|
QImage *normalImage,
|
||||||
|
|
|
@ -16,8 +16,8 @@ class GlbFileWriter : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
GlbFileWriter(Object &object,
|
GlbFileWriter(Object &object,
|
||||||
const std::vector<RiggerBone> *resultRigBones,
|
const std::vector<RigBone> *resultRigBones,
|
||||||
const std::map<int, RiggerVertexWeights> *resultRigWeights,
|
const std::map<int, RigVertexWeights> *resultRigWeights,
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
QImage *textureImage=nullptr,
|
QImage *textureImage=nullptr,
|
||||||
QImage *normalImage=nullptr,
|
QImage *normalImage=nullptr,
|
||||||
|
|
|
@ -36,7 +36,7 @@ void JointNodeTree::updateMatrix(int index, const QMatrix4x4 &matrix)
|
||||||
QQuaternion(scalar / length, x / length, y / length, z / length));
|
QQuaternion(scalar / length, x / length, y / length, z / length));
|
||||||
}
|
}
|
||||||
|
|
||||||
JointNodeTree::JointNodeTree(const std::vector<RiggerBone> *resultRigBones)
|
JointNodeTree::JointNodeTree(const std::vector<RigBone> *resultRigBones)
|
||||||
{
|
{
|
||||||
if (nullptr == resultRigBones || resultRigBones->empty())
|
if (nullptr == resultRigBones || resultRigBones->empty())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QQuaternion>
|
#include <QQuaternion>
|
||||||
#include "rigger.h"
|
#include "rig.h"
|
||||||
|
|
||||||
struct JointNode
|
struct JointNode
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ class JointNodeTree
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const std::vector<JointNode> &nodes() const;
|
const std::vector<JointNode> &nodes() const;
|
||||||
JointNodeTree(const std::vector<RiggerBone> *resultRigBones);
|
JointNodeTree(const std::vector<RigBone> *resultRigBones);
|
||||||
void updateRotation(int index, const QQuaternion &rotation);
|
void updateRotation(int index, const QQuaternion &rotation);
|
||||||
void updateTranslation(int index, const QVector3D &translation);
|
void updateTranslation(int index, const QVector3D &translation);
|
||||||
void updateMatrix(int index, const QMatrix4x4 &matrix);
|
void updateMatrix(int index, const QMatrix4x4 &matrix);
|
||||||
|
|
|
@ -187,8 +187,8 @@ void MotionEditWidget::save()
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotionEditWidget::updateBones(RigType rigType,
|
void MotionEditWidget::updateBones(RigType rigType,
|
||||||
const std::vector<RiggerBone> *rigBones,
|
const std::vector<RigBone> *rigBones,
|
||||||
const std::map<int, RiggerVertexWeights> *rigWeights,
|
const std::map<int, RigVertexWeights> *rigWeights,
|
||||||
const Object *object)
|
const Object *object)
|
||||||
{
|
{
|
||||||
m_rigType = rigType;
|
m_rigType = rigType;
|
||||||
|
@ -205,8 +205,8 @@ void MotionEditWidget::updateBones(RigType rigType,
|
||||||
if (nullptr != rigBones &&
|
if (nullptr != rigBones &&
|
||||||
nullptr != rigWeights &&
|
nullptr != rigWeights &&
|
||||||
nullptr != object) {
|
nullptr != object) {
|
||||||
m_bones = new std::vector<RiggerBone>(*rigBones);
|
m_bones = new std::vector<RigBone>(*rigBones);
|
||||||
m_rigWeights = new std::map<int, RiggerVertexWeights>(*rigWeights);
|
m_rigWeights = new std::map<int, RigVertexWeights>(*rigWeights);
|
||||||
m_object = new Object(*object);
|
m_object = new Object(*object);
|
||||||
|
|
||||||
generatePreview();
|
generatePreview();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include "vertebratamotion.h"
|
#include "vertebratamotion.h"
|
||||||
#include "rigger.h"
|
#include "rig.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
class SimpleShaderWidget;
|
class SimpleShaderWidget;
|
||||||
|
@ -31,8 +31,8 @@ public slots:
|
||||||
void generatePreview();
|
void generatePreview();
|
||||||
void previewReady();
|
void previewReady();
|
||||||
void updateBones(RigType rigType,
|
void updateBones(RigType rigType,
|
||||||
const std::vector<RiggerBone> *rigBones,
|
const std::vector<RigBone> *rigBones,
|
||||||
const std::map<int, RiggerVertexWeights> *rigWeights,
|
const std::map<int, RigVertexWeights> *rigWeights,
|
||||||
const Object *object);
|
const Object *object);
|
||||||
void setEditMotionName(const QString &name);
|
void setEditMotionName(const QString &name);
|
||||||
void setEditMotionId(const QUuid &motionId);
|
void setEditMotionId(const QUuid &motionId);
|
||||||
|
@ -55,8 +55,8 @@ private:
|
||||||
std::vector<SimpleShaderMesh *> m_frames;
|
std::vector<SimpleShaderMesh *> m_frames;
|
||||||
size_t m_frameIndex = 0;
|
size_t m_frameIndex = 0;
|
||||||
RigType m_rigType = RigType::None;
|
RigType m_rigType = RigType::None;
|
||||||
std::vector<RiggerBone> *m_bones = nullptr;
|
std::vector<RigBone> *m_bones = nullptr;
|
||||||
std::map<int, RiggerVertexWeights> *m_rigWeights = nullptr;
|
std::map<int, RigVertexWeights> *m_rigWeights = nullptr;
|
||||||
Object *m_object = nullptr;
|
Object *m_object = nullptr;
|
||||||
QLineEdit *m_nameEdit = nullptr;
|
QLineEdit *m_nameEdit = nullptr;
|
||||||
bool m_unsaved = false;
|
bool m_unsaved = false;
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
MotionsGenerator::MotionsGenerator(RigType rigType,
|
MotionsGenerator::MotionsGenerator(RigType rigType,
|
||||||
const std::vector<RiggerBone> &bones,
|
const std::vector<RigBone> &bones,
|
||||||
const std::map<int, RiggerVertexWeights> &rigWeights,
|
const std::map<int, RigVertexWeights> &rigWeights,
|
||||||
const Object &object) :
|
const Object &object) :
|
||||||
m_rigType(rigType),
|
m_rigType(rigType),
|
||||||
m_bones(bones),
|
m_bones(bones),
|
||||||
|
@ -252,7 +252,7 @@ void MotionsGenerator::generateMotion(const QUuid &motionId)
|
||||||
const auto &vertebrataMotionFrames = vertebrataMotion->frames();
|
const auto &vertebrataMotionFrames = vertebrataMotion->frames();
|
||||||
for (size_t frameIndex = 0; frameIndex < vertebrataMotionFrames.size(); ++frameIndex) {
|
for (size_t frameIndex = 0; frameIndex < vertebrataMotionFrames.size(); ++frameIndex) {
|
||||||
const auto &frame = vertebrataMotionFrames[frameIndex];
|
const auto &frame = vertebrataMotionFrames[frameIndex];
|
||||||
std::vector<RiggerBone> transformedBones = m_bones;
|
std::vector<RigBone> transformedBones = m_bones;
|
||||||
for (const auto &node: frame) {
|
for (const auto &node: frame) {
|
||||||
if (-1 == node.boneIndex)
|
if (-1 == node.boneIndex)
|
||||||
continue;
|
continue;
|
||||||
|
@ -326,7 +326,7 @@ void MotionsGenerator::generateMotion(const QUuid &motionId)
|
||||||
std::vector<QVector3D> transformedVertices(m_object.vertices.size());
|
std::vector<QVector3D> transformedVertices(m_object.vertices.size());
|
||||||
for (size_t i = 0; i < m_object.vertices.size(); ++i) {
|
for (size_t i = 0; i < m_object.vertices.size(); ++i) {
|
||||||
const auto &weight = m_rigWeights[i];
|
const auto &weight = m_rigWeights[i];
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < MAX_WEIGHT_NUM; x++) {
|
||||||
float factor = weight.boneWeights[x];
|
float factor = weight.boneWeights[x];
|
||||||
if (factor > 0) {
|
if (factor > 0) {
|
||||||
transformedVertices[i] += jointNodeMatrices[weight.boneIndices[x]] * m_object.vertices[i] * factor;
|
transformedVertices[i] += jointNodeMatrices[weight.boneIndices[x]] * m_object.vertices[i] * factor;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "simpleshadermesh.h"
|
#include "simpleshadermesh.h"
|
||||||
#include "rigger.h"
|
#include "rig.h"
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ class MotionsGenerator : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
MotionsGenerator(RigType rigType,
|
MotionsGenerator(RigType rigType,
|
||||||
const std::vector<RiggerBone> &bones,
|
const std::vector<RigBone> &bones,
|
||||||
const std::map<int, RiggerVertexWeights> &rigWeights,
|
const std::map<int, RigVertexWeights> &rigWeights,
|
||||||
const Object &object);
|
const Object &object);
|
||||||
~MotionsGenerator();
|
~MotionsGenerator();
|
||||||
void addMotion(const QUuid &motionId, const std::map<QString, QString> ¶meters);
|
void addMotion(const QUuid &motionId, const std::map<QString, QString> ¶meters);
|
||||||
|
@ -35,8 +35,8 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RigType m_rigType = RigType::None;
|
RigType m_rigType = RigType::None;
|
||||||
std::vector<RiggerBone> m_bones;
|
std::vector<RigBone> m_bones;
|
||||||
std::map<int, RiggerVertexWeights> m_rigWeights;
|
std::map<int, RigVertexWeights> m_rigWeights;
|
||||||
Object m_object;
|
Object m_object;
|
||||||
std::map<QUuid, std::map<QString, QString>> m_motions;
|
std::map<QUuid, std::map<QString, QString>> m_motions;
|
||||||
std::set<QUuid> m_generatedMotionIds;
|
std::set<QUuid> m_generatedMotionIds;
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#include "bonemark.h"
|
#include "bonemark.h"
|
||||||
#include "componentlayer.h"
|
#include "componentlayer.h"
|
||||||
|
|
||||||
#define MAX_WEIGHT_NUM 4
|
|
||||||
|
|
||||||
struct ObjectNode
|
struct ObjectNode
|
||||||
{
|
{
|
||||||
QUuid partId;
|
QUuid partId;
|
||||||
|
|
|
@ -273,7 +273,7 @@ void loadObjectFromXmlStream(Object *object, QXmlStreamReader &reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (reader.isEndElement()) {
|
} else if (reader.isEndElement()) {
|
||||||
if (fullName.startsWith("object.uvAreas")) {
|
if (fullName == "object.uvAreas") {
|
||||||
object->setPartUvRects(partUvRects);
|
object->setPartUvRects(partUvRects);
|
||||||
}
|
}
|
||||||
} else if (reader.isCharacters()) {
|
} else if (reader.isCharacters()) {
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "bonemark.h"
|
#include "bonemark.h"
|
||||||
#include "skeletonside.h"
|
#include "skeletonside.h"
|
||||||
#include "rigger.h"
|
#include "rig.h"
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef DUST3D_RIGGER_H
|
#ifndef DUST3D_RIG_H
|
||||||
#define DUST3D_RIGGER_H
|
#define DUST3D_RIG_H
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
@ -11,12 +11,9 @@
|
||||||
#include "rigtype.h"
|
#include "rigtype.h"
|
||||||
#include "skeletonside.h"
|
#include "skeletonside.h"
|
||||||
|
|
||||||
namespace Rigger
|
#define MAX_WEIGHT_NUM 4
|
||||||
{
|
|
||||||
const QString rootBoneName = "Body";
|
|
||||||
};
|
|
||||||
|
|
||||||
class RiggerBone
|
class RigBone
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QString name;
|
QString name;
|
||||||
|
@ -31,11 +28,11 @@ public:
|
||||||
std::vector<int> children;
|
std::vector<int> children;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RiggerVertexWeights
|
class RigVertexWeights
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int boneIndices[4] = {0, 0, 0, 0};
|
int boneIndices[MAX_WEIGHT_NUM] = {0};
|
||||||
float boneWeights[4] = {0, 0, 0, 0};
|
float boneWeights[MAX_WEIGHT_NUM] = {0};
|
||||||
void addBone(int boneIndex, float weight)
|
void addBone(int boneIndex, float weight)
|
||||||
{
|
{
|
||||||
for (auto &it: m_boneRawWeights) {
|
for (auto &it: m_boneRawWeights) {
|
||||||
|
@ -53,12 +50,12 @@ public:
|
||||||
return a.second > b.second;
|
return a.second > b.second;
|
||||||
});
|
});
|
||||||
float totalWeight = 0;
|
float totalWeight = 0;
|
||||||
for (size_t i = 0; i < m_boneRawWeights.size() && i < 4; i++) {
|
for (size_t i = 0; i < m_boneRawWeights.size() && i < MAX_WEIGHT_NUM; i++) {
|
||||||
const auto &item = m_boneRawWeights[i];
|
const auto &item = m_boneRawWeights[i];
|
||||||
totalWeight += item.second;
|
totalWeight += item.second;
|
||||||
}
|
}
|
||||||
if (totalWeight > 0) {
|
if (totalWeight > 0) {
|
||||||
for (size_t i = 0; i < m_boneRawWeights.size() && i < 4; i++) {
|
for (size_t i = 0; i < m_boneRawWeights.size() && i < MAX_WEIGHT_NUM; i++) {
|
||||||
const auto &item = m_boneRawWeights[i];
|
const auto &item = m_boneRawWeights[i];
|
||||||
boneIndices[i] = item.first;
|
boneIndices[i] = item.first;
|
||||||
boneWeights[i] = item.second / totalWeight;
|
boneWeights[i] = item.second / totalWeight;
|
|
@ -80,16 +80,16 @@ Object *RigGenerator::takeObject()
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<RiggerBone> *RigGenerator::takeResultBones()
|
std::vector<RigBone> *RigGenerator::takeResultBones()
|
||||||
{
|
{
|
||||||
std::vector<RiggerBone> *resultBones = m_resultBones;
|
std::vector<RigBone> *resultBones = m_resultBones;
|
||||||
m_resultBones = nullptr;
|
m_resultBones = nullptr;
|
||||||
return resultBones;
|
return resultBones;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, RiggerVertexWeights> *RigGenerator::takeResultWeights()
|
std::map<int, RigVertexWeights> *RigGenerator::takeResultWeights()
|
||||||
{
|
{
|
||||||
std::map<int, RiggerVertexWeights> *resultWeights = m_resultWeights;
|
std::map<int, RigVertexWeights> *resultWeights = m_resultWeights;
|
||||||
m_resultWeights = nullptr;
|
m_resultWeights = nullptr;
|
||||||
return resultWeights;
|
return resultWeights;
|
||||||
}
|
}
|
||||||
|
@ -408,12 +408,12 @@ void RigGenerator::buildSkeleton()
|
||||||
m_rootSpineJointIndex = m_attachLimbsToSpineJointIndices[0];
|
m_rootSpineJointIndex = m_attachLimbsToSpineJointIndices[0];
|
||||||
m_lastSpineJointIndex = m_spineJoints.size() - 1;
|
m_lastSpineJointIndex = m_spineJoints.size() - 1;
|
||||||
|
|
||||||
m_resultBones = new std::vector<RiggerBone>;
|
m_resultBones = new std::vector<RigBone>;
|
||||||
m_resultWeights = new std::map<int, RiggerVertexWeights>;
|
m_resultWeights = new std::map<int, RigVertexWeights>;
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto &firstSpineNode = m_object->nodes[m_spineJoints[m_rootSpineJointIndex]];
|
const auto &firstSpineNode = m_object->nodes[m_spineJoints[m_rootSpineJointIndex]];
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = QVector3D(0.0, 0.0, 0.0);
|
bone.headPosition = QVector3D(0.0, 0.0, 0.0);
|
||||||
bone.tailPosition = firstSpineNode.origin;
|
bone.tailPosition = firstSpineNode.origin;
|
||||||
bone.headRadius = 0;
|
bone.headRadius = 0;
|
||||||
|
@ -432,7 +432,7 @@ void RigGenerator::buildSkeleton()
|
||||||
++spineJointIndex) {
|
++spineJointIndex) {
|
||||||
const auto ¤tNode = m_object->nodes[m_spineJoints[spineJointIndex]];
|
const auto ¤tNode = m_object->nodes[m_spineJoints[spineJointIndex]];
|
||||||
const auto &nextNode = m_object->nodes[m_spineJoints[spineJointIndex + 1]];
|
const auto &nextNode = m_object->nodes[m_spineJoints[spineJointIndex + 1]];
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = currentNode.origin;
|
bone.headPosition = currentNode.origin;
|
||||||
bone.tailPosition = nextNode.origin;
|
bone.tailPosition = nextNode.origin;
|
||||||
bone.headRadius = currentNode.radius;
|
bone.headRadius = currentNode.radius;
|
||||||
|
@ -454,7 +454,7 @@ void RigGenerator::buildSkeleton()
|
||||||
const auto &spineNode = m_object->nodes[m_spineJoints[spineJointIndex]];
|
const auto &spineNode = m_object->nodes[m_spineJoints[spineJointIndex]];
|
||||||
const auto &limbFirstNode = m_object->nodes[limbJoints[limbIndex][0]];
|
const auto &limbFirstNode = m_object->nodes[limbJoints[limbIndex][0]];
|
||||||
const auto &parentIndex = attachedBoneIndex(spineJointIndex);
|
const auto &parentIndex = attachedBoneIndex(spineJointIndex);
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = spineNode.origin;
|
bone.headPosition = spineNode.origin;
|
||||||
bone.tailPosition = limbFirstNode.origin;
|
bone.tailPosition = limbFirstNode.origin;
|
||||||
bone.headRadius = spineNode.radius;
|
bone.headRadius = spineNode.radius;
|
||||||
|
@ -478,7 +478,7 @@ void RigGenerator::buildSkeleton()
|
||||||
++limbJointIndex) {
|
++limbJointIndex) {
|
||||||
const auto ¤tNode = m_object->nodes[joints[limbJointIndex]];
|
const auto ¤tNode = m_object->nodes[joints[limbJointIndex]];
|
||||||
const auto &nextNode = m_object->nodes[joints[limbJointIndex + 1]];
|
const auto &nextNode = m_object->nodes[joints[limbJointIndex + 1]];
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = currentNode.origin;
|
bone.headPosition = currentNode.origin;
|
||||||
bone.tailPosition = nextNode.origin;
|
bone.tailPosition = nextNode.origin;
|
||||||
bone.headRadius = currentNode.radius;
|
bone.headRadius = currentNode.radius;
|
||||||
|
@ -516,7 +516,7 @@ void RigGenerator::buildSkeleton()
|
||||||
++neckJointIndex) {
|
++neckJointIndex) {
|
||||||
const auto ¤tNode = m_object->nodes[m_neckJoints[neckJointIndex]];
|
const auto ¤tNode = m_object->nodes[m_neckJoints[neckJointIndex]];
|
||||||
const auto &nextNode = m_object->nodes[m_neckJoints[neckJointIndex + 1]];
|
const auto &nextNode = m_object->nodes[m_neckJoints[neckJointIndex + 1]];
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = currentNode.origin;
|
bone.headPosition = currentNode.origin;
|
||||||
bone.tailPosition = nextNode.origin;
|
bone.tailPosition = nextNode.origin;
|
||||||
bone.headRadius = currentNode.radius;
|
bone.headRadius = currentNode.radius;
|
||||||
|
@ -548,7 +548,7 @@ void RigGenerator::buildSkeleton()
|
||||||
const auto &nextNode = spineJointIndex > 0 ?
|
const auto &nextNode = spineJointIndex > 0 ?
|
||||||
m_object->nodes[m_spineJoints[spineJointIndex - 1]] :
|
m_object->nodes[m_spineJoints[spineJointIndex - 1]] :
|
||||||
m_object->nodes[m_tailJoints[0]];
|
m_object->nodes[m_tailJoints[0]];
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = currentNode.origin;
|
bone.headPosition = currentNode.origin;
|
||||||
bone.tailPosition = nextNode.origin;
|
bone.tailPosition = nextNode.origin;
|
||||||
bone.headRadius = currentNode.radius;
|
bone.headRadius = currentNode.radius;
|
||||||
|
@ -574,7 +574,7 @@ void RigGenerator::buildSkeleton()
|
||||||
++tailJointIndex) {
|
++tailJointIndex) {
|
||||||
const auto ¤tNode = m_object->nodes[m_tailJoints[tailJointIndex]];
|
const auto ¤tNode = m_object->nodes[m_tailJoints[tailJointIndex]];
|
||||||
const auto &nextNode = m_object->nodes[m_tailJoints[tailJointIndex + 1]];
|
const auto &nextNode = m_object->nodes[m_tailJoints[tailJointIndex + 1]];
|
||||||
RiggerBone bone;
|
RigBone bone;
|
||||||
bone.headPosition = currentNode.origin;
|
bone.headPosition = currentNode.origin;
|
||||||
bone.tailPosition = nextNode.origin;
|
bone.tailPosition = nextNode.origin;
|
||||||
bone.headRadius = currentNode.radius;
|
bone.headRadius = currentNode.radius;
|
||||||
|
@ -1190,17 +1190,17 @@ void RigGenerator::buildDemoMesh()
|
||||||
const auto &resultWeights = *m_resultWeights;
|
const auto &resultWeights = *m_resultWeights;
|
||||||
const auto &resultBones = *m_resultBones;
|
const auto &resultBones = *m_resultBones;
|
||||||
|
|
||||||
m_resultWeights = new std::map<int, RiggerVertexWeights>;
|
m_resultWeights = new std::map<int, RigVertexWeights>;
|
||||||
*m_resultWeights = resultWeights;
|
*m_resultWeights = resultWeights;
|
||||||
|
|
||||||
m_resultBones = new std::vector<RiggerBone>;
|
m_resultBones = new std::vector<RigBone>;
|
||||||
*m_resultBones = resultBones;
|
*m_resultBones = resultBones;
|
||||||
|
|
||||||
for (const auto &weightItem: resultWeights) {
|
for (const auto &weightItem: resultWeights) {
|
||||||
size_t vertexIndex = weightItem.first;
|
size_t vertexIndex = weightItem.first;
|
||||||
const auto &weight = weightItem.second;
|
const auto &weight = weightItem.second;
|
||||||
int blendR = 0, blendG = 0, blendB = 0;
|
int blendR = 0, blendG = 0, blendB = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < MAX_WEIGHT_NUM; i++) {
|
||||||
int boneIndex = weight.boneIndices[i];
|
int boneIndex = weight.boneIndices[i];
|
||||||
const auto &bone = resultBones[boneIndex];
|
const auto &bone = resultBones[boneIndex];
|
||||||
blendR += bone.color.red() * weight.boneWeights[i];
|
blendR += bone.color.red() * weight.boneWeights[i];
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "rigger.h"
|
#include "rig.h"
|
||||||
#include "rigtype.h"
|
#include "rigtype.h"
|
||||||
|
|
||||||
class RigGenerator : public QObject
|
class RigGenerator : public QObject
|
||||||
|
@ -16,8 +16,8 @@ public:
|
||||||
RigGenerator(RigType rigType, const Object &object);
|
RigGenerator(RigType rigType, const Object &object);
|
||||||
~RigGenerator();
|
~RigGenerator();
|
||||||
Model *takeResultMesh();
|
Model *takeResultMesh();
|
||||||
std::vector<RiggerBone> *takeResultBones();
|
std::vector<RigBone> *takeResultBones();
|
||||||
std::map<int, RiggerVertexWeights> *takeResultWeights();
|
std::map<int, RigVertexWeights> *takeResultWeights();
|
||||||
const std::vector<std::pair<QtMsgType, QString>> &messages();
|
const std::vector<std::pair<QtMsgType, QString>> &messages();
|
||||||
Object *takeObject();
|
Object *takeObject();
|
||||||
bool isSuccessful();
|
bool isSuccessful();
|
||||||
|
@ -38,8 +38,8 @@ private:
|
||||||
RigType m_rigType = RigType::None;
|
RigType m_rigType = RigType::None;
|
||||||
Object *m_object = nullptr;
|
Object *m_object = nullptr;
|
||||||
Model *m_resultMesh = nullptr;
|
Model *m_resultMesh = nullptr;
|
||||||
std::vector<RiggerBone> *m_resultBones = nullptr;
|
std::vector<RigBone> *m_resultBones = nullptr;
|
||||||
std::map<int, RiggerVertexWeights> *m_resultWeights = nullptr;
|
std::map<int, RigVertexWeights> *m_resultWeights = nullptr;
|
||||||
std::vector<std::pair<QtMsgType, QString>> m_messages;
|
std::vector<std::pair<QtMsgType, QString>> m_messages;
|
||||||
std::map<size_t, std::unordered_set<size_t>> m_neighborMap;
|
std::map<size_t, std::unordered_set<size_t>> m_neighborMap;
|
||||||
std::vector<BoneNodeChain> m_boneNodeChain;
|
std::vector<BoneNodeChain> m_boneNodeChain;
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include <stack>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QRegExp>
|
||||||
|
#include "rigxml.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "jointnodetree.h"
|
||||||
|
|
||||||
|
void saveRigToXmlStream(const Object *object,
|
||||||
|
const std::vector<RigBone> *rigBones,
|
||||||
|
const std::map<int, RigVertexWeights> *rigWeights,
|
||||||
|
QXmlStreamWriter *writer)
|
||||||
|
{
|
||||||
|
JointNodeTree jointNodeTree(rigBones);
|
||||||
|
const auto &boneNodes = jointNodeTree.nodes();
|
||||||
|
|
||||||
|
writer->setAutoFormatting(true);
|
||||||
|
writer->writeStartDocument();
|
||||||
|
|
||||||
|
writer->writeStartElement("rig");
|
||||||
|
writer->writeStartElement("bones");
|
||||||
|
for (size_t boneIndex = 0; boneIndex < rigBones->size(); ++boneIndex) {
|
||||||
|
const auto &bone = (*rigBones)[boneIndex];
|
||||||
|
const auto &node = boneNodes[boneIndex];
|
||||||
|
writer->writeStartElement("bone");
|
||||||
|
writer->writeAttribute("name", bone.name);
|
||||||
|
writer->writeAttribute("parentIndex", QString::number(bone.parent));
|
||||||
|
writer->writeAttribute("headX", QString::number(bone.headPosition.x()));
|
||||||
|
writer->writeAttribute("headY", QString::number(bone.headPosition.y()));
|
||||||
|
writer->writeAttribute("headZ", QString::number(bone.headPosition.z()));
|
||||||
|
writer->writeAttribute("tailX", QString::number(bone.tailPosition.x()));
|
||||||
|
writer->writeAttribute("tailY", QString::number(bone.tailPosition.y()));
|
||||||
|
writer->writeAttribute("tailZ", QString::number(bone.tailPosition.z()));
|
||||||
|
writer->writeAttribute("headRadius", QString::number(bone.headRadius));
|
||||||
|
writer->writeAttribute("tailRadius", QString::number(bone.tailRadius));
|
||||||
|
writer->writeAttribute("color", bone.color.name(QColor::HexArgb));
|
||||||
|
for (const auto &attribute: bone.attributes)
|
||||||
|
writer->writeAttribute(attribute.first, attribute.second);
|
||||||
|
const float *floatArray = node.inverseBindMatrix.constData();
|
||||||
|
QStringList matrixItemList;
|
||||||
|
for (auto j = 0u; j < 16; j++) {
|
||||||
|
matrixItemList += QString::number(floatArray[j]);
|
||||||
|
}
|
||||||
|
writer->writeAttribute("inverseBindMatrix", matrixItemList.join(","));
|
||||||
|
writer->writeEndElement();
|
||||||
|
}
|
||||||
|
writer->writeEndElement();
|
||||||
|
|
||||||
|
writer->writeStartElement("weights");
|
||||||
|
QStringList weightsList;
|
||||||
|
for (size_t vertexIndex = 0; vertexIndex < object->vertices.size(); ++vertexIndex) {
|
||||||
|
auto findWeights = rigWeights->find(vertexIndex);
|
||||||
|
if (findWeights == rigWeights->end()) {
|
||||||
|
QStringList vertexWeightsList;
|
||||||
|
for (size_t i = 0; i < MAX_WEIGHT_NUM; ++i) {
|
||||||
|
vertexWeightsList += "0,0";
|
||||||
|
}
|
||||||
|
weightsList += vertexWeightsList.join(",");
|
||||||
|
} else {
|
||||||
|
QStringList vertexWeightsList;
|
||||||
|
for (size_t i = 0; i < MAX_WEIGHT_NUM; ++i) {
|
||||||
|
vertexWeightsList += QString::number(findWeights->second.boneIndices[i]) + "," + QString::number(findWeights->second.boneWeights[i]);
|
||||||
|
}
|
||||||
|
weightsList += vertexWeightsList.join(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer->writeCharacters(weightsList.join(" "));
|
||||||
|
writer->writeEndElement();
|
||||||
|
|
||||||
|
writer->writeEndElement();
|
||||||
|
writer->writeEndDocument();
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef DUST3D_RIG_XML_H
|
||||||
|
#define DUST3D_RIG_XML_H
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
#include "rig.h"
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
void saveRigToXmlStream(const Object *object,
|
||||||
|
const std::vector<RigBone> *rigBones,
|
||||||
|
const std::map<int, RigVertexWeights> *rigWeights,
|
||||||
|
QXmlStreamWriter *writer);
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,7 +2,7 @@
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
|
||||||
SkinnedMeshCreator::SkinnedMeshCreator(const Object &object,
|
SkinnedMeshCreator::SkinnedMeshCreator(const Object &object,
|
||||||
const std::map<int, RiggerVertexWeights> &resultWeights) :
|
const std::map<int, RigVertexWeights> &resultWeights) :
|
||||||
m_object(object),
|
m_object(object),
|
||||||
m_resultWeights(resultWeights)
|
m_resultWeights(resultWeights)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ Model *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatrix4x4>
|
||||||
QMatrix4x4 mixedMatrix;
|
QMatrix4x4 mixedMatrix;
|
||||||
transformedPositions[i][j] = QVector3D();
|
transformedPositions[i][j] = QVector3D();
|
||||||
transformedPoseNormals[i][j] = QVector3D();
|
transformedPoseNormals[i][j] = QVector3D();
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int x = 0; x < MAX_WEIGHT_NUM; x++) {
|
||||||
float factor = weight.boneWeights[x];
|
float factor = weight.boneWeights[x];
|
||||||
if (factor > 0) {
|
if (factor > 0) {
|
||||||
transformedPositions[i][j] += matricies[weight.boneIndices[x]] * m_verticesBindPositions[i][j] * factor;
|
transformedPositions[i][j] += matricies[weight.boneIndices[x]] * m_verticesBindPositions[i][j] * factor;
|
||||||
|
|
|
@ -12,11 +12,11 @@ class SkinnedMeshCreator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SkinnedMeshCreator(const Object &object,
|
SkinnedMeshCreator(const Object &object,
|
||||||
const std::map<int, RiggerVertexWeights> &resultWeights);
|
const std::map<int, RigVertexWeights> &resultWeights);
|
||||||
Model *createMeshFromTransform(const std::vector<QMatrix4x4> &matricies);
|
Model *createMeshFromTransform(const std::vector<QMatrix4x4> &matricies);
|
||||||
private:
|
private:
|
||||||
Object m_object;
|
Object m_object;
|
||||||
std::map<int, RiggerVertexWeights> m_resultWeights;
|
std::map<int, RigVertexWeights> m_resultWeights;
|
||||||
std::vector<std::vector<int>> m_verticesOldIndices;
|
std::vector<std::vector<int>> m_verticesOldIndices;
|
||||||
std::vector<std::vector<QVector3D>> m_verticesBindPositions;
|
std::vector<std::vector<QVector3D>> m_verticesBindPositions;
|
||||||
std::vector<std::vector<QVector3D>> m_verticesBindNormals;
|
std::vector<std::vector<QVector3D>> m_verticesBindNormals;
|
||||||
|
|
Loading…
Reference in New Issue