diff --git a/dust3d.pro b/dust3d.pro index fdf3f9b2..74a9df47 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -260,8 +260,8 @@ HEADERS += src/skeletonside.h SOURCES += src/meshsplitter.cpp HEADERS += src/meshsplitter.h -SOURCES += src/rigger.cpp -HEADERS += src/rigger.h +SOURCES += src/rig.cpp +HEADERS += src/rig.h SOURCES += src/rigtype.cpp HEADERS += src/rigtype.h @@ -526,6 +526,9 @@ HEADERS += src/vertebratamotionparameterswidget.h SOURCES += src/objectxml.cpp HEADERS += src/objectxml.h +SOURCES += src/rigxml.cpp +HEADERS += src/rigxml.h + SOURCES += src/main.cpp HEADERS += src/version.h diff --git a/src/document.cpp b/src/document.cpp index 38ced8ef..1990d7de 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -3579,12 +3579,12 @@ void Document::rigReady() } } -const std::vector *Document::resultRigBones() const +const std::vector *Document::resultRigBones() const { return m_resultRigBones; } -const std::map *Document::resultRigWeights() const +const std::map *Document::resultRigWeights() const { return m_resultRigWeights; } @@ -3643,8 +3643,8 @@ void Document::generateMotions() return; } - const std::vector *rigBones = resultRigBones(); - const std::map *rigWeights = resultRigWeights(); + const std::vector *rigBones = resultRigBones(); + const std::map *rigWeights = resultRigWeights(); if (nullptr == rigBones || nullptr == rigWeights) { return; diff --git a/src/document.h b/src/document.h index 7cb2c634..a99d7d1a 100644 --- a/src/document.h +++ b/src/document.h @@ -470,8 +470,8 @@ public: bool isMeshGenerationSucceed(); Model *takeResultTextureMesh(); Model *takeResultRigWeightMesh(); - const std::vector *resultRigBones() const; - const std::map *resultRigWeights() const; + const std::vector *resultRigBones() const; + const std::map *resultRigWeights() const; void updateTurnaround(const QImage &image); void updateTextureImage(QImage *image); void updateTextureNormalImage(QImage *image); @@ -684,8 +684,8 @@ private: // need initialize bool m_smoothNormal; RigGenerator *m_rigGenerator; Model *m_resultRigWeightMesh; - std::vector *m_resultRigBones; - std::map *m_resultRigWeights; + std::vector *m_resultRigBones; + std::map *m_resultRigWeights; bool m_isRigObsolete; Object *m_riggedObject; bool m_currentRigSucceed; diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp index 3ac34ec0..3f0ec6c6 100644 --- a/src/documentwindow.cpp +++ b/src/documentwindow.cpp @@ -49,6 +49,7 @@ #include "fileforever.h" #include "documentsaver.h" #include "objectxml.h" +#include "rigxml.h" int DocumentWindow::m_autoRecovered = false; @@ -584,6 +585,10 @@ DocumentWindow::DocumentWindow() : connect(m_exportTexturesAction, &QAction::triggered, this, &DocumentWindow::exportTextures, Qt::QueuedConnection); 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); connect(m_exportRenderedAsImageAction, &QAction::triggered, this, &DocumentWindow::exportRenderedResult, Qt::QueuedConnection); m_fileMenu->addAction(m_exportRenderedAsImageAction); @@ -605,6 +610,7 @@ DocumentWindow::DocumentWindow() : m_exportAsGlbAction->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_exportDs3objAction->setEnabled(m_graphicsWidget->hasItems() && m_document->isExportReady()); m_exportRenderedAsImageAction->setEnabled(m_graphicsWidget->hasItems()); }); @@ -1871,12 +1877,14 @@ void DocumentWindow::openPathAs(const QString &path, const QString &asName) for (int i = 0; i < ds3Reader.items().size(); ++i) { Ds3ReaderItem item = ds3Reader.items().at(i); if (item.type == "object") { - QByteArray data; - ds3Reader.loadItem(item.name, &data); - QXmlStreamReader stream(data); - Object *object = new Object; - loadObjectFromXmlStream(object, stream); - m_document->updateObject(object); + if (item.name == "object.xml") { + QByteArray data; + ds3Reader.loadItem(item.name, &data); + QXmlStreamReader stream(data); + Object *object = new Object; + loadObjectFromXmlStream(object, stream); + m_document->updateObject(object); + } } } } @@ -2045,6 +2053,17 @@ void DocumentWindow::exportGlbResult() 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) { if (!m_document->isExportReady()) { @@ -2068,6 +2087,101 @@ void DocumentWindow::exportGlbToFilename(const QString &filename) 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 *rigBones = m_document->resultRigBones(); + const std::map *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() { if (m_document->xlocked) diff --git a/src/documentwindow.h b/src/documentwindow.h index 41674679..ba52e07b 100644 --- a/src/documentwindow.h +++ b/src/documentwindow.h @@ -61,6 +61,7 @@ public slots: void exportGlbResult(); void exportFbxResult(); void exportTextures(); + void exportDs3objResult(); void newWindow(); void newDocument(); void saveAs(); @@ -92,6 +93,7 @@ public slots: void exportFbxToFilename(const QString &filename); void exportGlbToFilename(const QString &filename); void exportTexturesToDirectory(const QString &directory); + void exportDs3objToFilename(const QString &filename); void toggleRotation(); //void updateInfoWidgetPosition(); void generateNormalAndDepthMaps(); @@ -146,6 +148,7 @@ private: QAction *m_exportAsGlbAction; QAction *m_exportAsFbxAction; QAction *m_exportTexturesAction; + QAction *m_exportDs3objAction; QAction *m_exportRenderedAsImageAction; QMenu *m_editMenu; diff --git a/src/fbxfile.cpp b/src/fbxfile.cpp index cd5fbdd0..7f849b58 100644 --- a/src/fbxfile.cpp +++ b/src/fbxfile.cpp @@ -2201,8 +2201,8 @@ void FbxFileWriter::createDefinitions(size_t deformerCount, } FbxFileWriter::FbxFileWriter(Object &object, - const std::vector *resultRigBones, - const std::map *resultRigWeights, + const std::vector *resultRigBones, + const std::map *resultRigWeights, const QString &filename, QImage *textureImage, QImage *normalImage, @@ -2415,7 +2415,7 @@ FbxFileWriter::FbxFileWriter(Object &object, std::vector, std::vector>> bindPerBone(resultRigBones->size()); if (resultRigWeights && !resultRigWeights->empty()) { 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]; Q_ASSERT(boneIndex < bindPerBone.size()); if (0 == boneIndex) diff --git a/src/fbxfile.h b/src/fbxfile.h index f7cd9d79..40d536d7 100644 --- a/src/fbxfile.h +++ b/src/fbxfile.h @@ -14,8 +14,8 @@ class FbxFileWriter : public QObject Q_OBJECT public: FbxFileWriter(Object &object, - const std::vector *resultRigBones, - const std::map *resultRigWeights, + const std::vector *resultRigBones, + const std::map *resultRigWeights, const QString &filename, QImage *textureImage=nullptr, QImage *normalImage=nullptr, diff --git a/src/glbfile.cpp b/src/glbfile.cpp index 41bc4408..792fbcfa 100644 --- a/src/glbfile.cpp +++ b/src/glbfile.cpp @@ -23,8 +23,8 @@ bool GlbFileWriter::m_enableComment = false; GlbFileWriter::GlbFileWriter(Object &object, - const std::vector *resultRigBones, - const std::map *resultRigWeights, + const std::vector *resultRigBones, + const std::map *resultRigWeights, const QString &filename, QImage *textureImage, QImage *normalImage, diff --git a/src/glbfile.h b/src/glbfile.h index 457ea79a..eed0fcd7 100644 --- a/src/glbfile.h +++ b/src/glbfile.h @@ -16,8 +16,8 @@ class GlbFileWriter : public QObject Q_OBJECT public: GlbFileWriter(Object &object, - const std::vector *resultRigBones, - const std::map *resultRigWeights, + const std::vector *resultRigBones, + const std::map *resultRigWeights, const QString &filename, QImage *textureImage=nullptr, QImage *normalImage=nullptr, diff --git a/src/jointnodetree.cpp b/src/jointnodetree.cpp index 4a7ba934..7852ca8d 100644 --- a/src/jointnodetree.cpp +++ b/src/jointnodetree.cpp @@ -36,7 +36,7 @@ void JointNodeTree::updateMatrix(int index, const QMatrix4x4 &matrix) QQuaternion(scalar / length, x / length, y / length, z / length)); } -JointNodeTree::JointNodeTree(const std::vector *resultRigBones) +JointNodeTree::JointNodeTree(const std::vector *resultRigBones) { if (nullptr == resultRigBones || resultRigBones->empty()) return; diff --git a/src/jointnodetree.h b/src/jointnodetree.h index 4b5f1c0a..85d01ddb 100644 --- a/src/jointnodetree.h +++ b/src/jointnodetree.h @@ -3,7 +3,7 @@ #include #include #include -#include "rigger.h" +#include "rig.h" struct JointNode { @@ -22,7 +22,7 @@ class JointNodeTree { public: const std::vector &nodes() const; - JointNodeTree(const std::vector *resultRigBones); + JointNodeTree(const std::vector *resultRigBones); void updateRotation(int index, const QQuaternion &rotation); void updateTranslation(int index, const QVector3D &translation); void updateMatrix(int index, const QMatrix4x4 &matrix); diff --git a/src/motioneditwidget.cpp b/src/motioneditwidget.cpp index 55714dcc..f4799a36 100644 --- a/src/motioneditwidget.cpp +++ b/src/motioneditwidget.cpp @@ -187,8 +187,8 @@ void MotionEditWidget::save() } void MotionEditWidget::updateBones(RigType rigType, - const std::vector *rigBones, - const std::map *rigWeights, + const std::vector *rigBones, + const std::map *rigWeights, const Object *object) { m_rigType = rigType; @@ -205,8 +205,8 @@ void MotionEditWidget::updateBones(RigType rigType, if (nullptr != rigBones && nullptr != rigWeights && nullptr != object) { - m_bones = new std::vector(*rigBones); - m_rigWeights = new std::map(*rigWeights); + m_bones = new std::vector(*rigBones); + m_rigWeights = new std::map(*rigWeights); m_object = new Object(*object); generatePreview(); diff --git a/src/motioneditwidget.h b/src/motioneditwidget.h index def0e4e7..251bcc1c 100644 --- a/src/motioneditwidget.h +++ b/src/motioneditwidget.h @@ -6,7 +6,7 @@ #include #include #include "vertebratamotion.h" -#include "rigger.h" +#include "rig.h" #include "object.h" class SimpleShaderWidget; @@ -31,8 +31,8 @@ public slots: void generatePreview(); void previewReady(); void updateBones(RigType rigType, - const std::vector *rigBones, - const std::map *rigWeights, + const std::vector *rigBones, + const std::map *rigWeights, const Object *object); void setEditMotionName(const QString &name); void setEditMotionId(const QUuid &motionId); @@ -55,8 +55,8 @@ private: std::vector m_frames; size_t m_frameIndex = 0; RigType m_rigType = RigType::None; - std::vector *m_bones = nullptr; - std::map *m_rigWeights = nullptr; + std::vector *m_bones = nullptr; + std::map *m_rigWeights = nullptr; Object *m_object = nullptr; QLineEdit *m_nameEdit = nullptr; bool m_unsaved = false; diff --git a/src/motionsgenerator.cpp b/src/motionsgenerator.cpp index 733a2360..e6ab3b52 100644 --- a/src/motionsgenerator.cpp +++ b/src/motionsgenerator.cpp @@ -10,8 +10,8 @@ #include "util.h" MotionsGenerator::MotionsGenerator(RigType rigType, - const std::vector &bones, - const std::map &rigWeights, + const std::vector &bones, + const std::map &rigWeights, const Object &object) : m_rigType(rigType), m_bones(bones), @@ -252,7 +252,7 @@ void MotionsGenerator::generateMotion(const QUuid &motionId) const auto &vertebrataMotionFrames = vertebrataMotion->frames(); for (size_t frameIndex = 0; frameIndex < vertebrataMotionFrames.size(); ++frameIndex) { const auto &frame = vertebrataMotionFrames[frameIndex]; - std::vector transformedBones = m_bones; + std::vector transformedBones = m_bones; for (const auto &node: frame) { if (-1 == node.boneIndex) continue; @@ -326,7 +326,7 @@ void MotionsGenerator::generateMotion(const QUuid &motionId) std::vector transformedVertices(m_object.vertices.size()); for (size_t i = 0; i < m_object.vertices.size(); ++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]; if (factor > 0) { transformedVertices[i] += jointNodeMatrices[weight.boneIndices[x]] * m_object.vertices[i] * factor; diff --git a/src/motionsgenerator.h b/src/motionsgenerator.h index f2dcf566..1431d29e 100644 --- a/src/motionsgenerator.h +++ b/src/motionsgenerator.h @@ -6,7 +6,7 @@ #include #include "model.h" #include "simpleshadermesh.h" -#include "rigger.h" +#include "rig.h" #include "jointnodetree.h" #include "document.h" @@ -15,8 +15,8 @@ class MotionsGenerator : public QObject Q_OBJECT public: MotionsGenerator(RigType rigType, - const std::vector &bones, - const std::map &rigWeights, + const std::vector &bones, + const std::map &rigWeights, const Object &object); ~MotionsGenerator(); void addMotion(const QUuid &motionId, const std::map ¶meters); @@ -35,8 +35,8 @@ public slots: private: RigType m_rigType = RigType::None; - std::vector m_bones; - std::map m_rigWeights; + std::vector m_bones; + std::map m_rigWeights; Object m_object; std::map> m_motions; std::set m_generatedMotionIds; diff --git a/src/object.h b/src/object.h index 611b003a..e883caef 100644 --- a/src/object.h +++ b/src/object.h @@ -10,8 +10,6 @@ #include "bonemark.h" #include "componentlayer.h" -#define MAX_WEIGHT_NUM 4 - struct ObjectNode { QUuid partId; diff --git a/src/objectxml.cpp b/src/objectxml.cpp index 59758edd..05ddc039 100644 --- a/src/objectxml.cpp +++ b/src/objectxml.cpp @@ -273,7 +273,7 @@ void loadObjectFromXmlStream(Object *object, QXmlStreamReader &reader) } } } else if (reader.isEndElement()) { - if (fullName.startsWith("object.uvAreas")) { + if (fullName == "object.uvAreas") { object->setPartUvRects(partUvRects); } } else if (reader.isCharacters()) { diff --git a/src/rigger.cpp b/src/rig.cpp similarity index 83% rename from src/rigger.cpp rename to src/rig.cpp index 47a71769..f1ce344b 100644 --- a/src/rigger.cpp +++ b/src/rig.cpp @@ -3,4 +3,4 @@ #include "theme.h" #include "bonemark.h" #include "skeletonside.h" -#include "rigger.h" +#include "rig.h" diff --git a/src/rigger.h b/src/rig.h similarity index 83% rename from src/rigger.h rename to src/rig.h index 10b26f65..aa2571d8 100644 --- a/src/rigger.h +++ b/src/rig.h @@ -1,5 +1,5 @@ -#ifndef DUST3D_RIGGER_H -#define DUST3D_RIGGER_H +#ifndef DUST3D_RIG_H +#define DUST3D_RIG_H #include #include #include @@ -11,12 +11,9 @@ #include "rigtype.h" #include "skeletonside.h" -namespace Rigger -{ - const QString rootBoneName = "Body"; -}; +#define MAX_WEIGHT_NUM 4 -class RiggerBone +class RigBone { public: QString name; @@ -31,11 +28,11 @@ public: std::vector children; }; -class RiggerVertexWeights +class RigVertexWeights { public: - int boneIndices[4] = {0, 0, 0, 0}; - float boneWeights[4] = {0, 0, 0, 0}; + int boneIndices[MAX_WEIGHT_NUM] = {0}; + float boneWeights[MAX_WEIGHT_NUM] = {0}; void addBone(int boneIndex, float weight) { for (auto &it: m_boneRawWeights) { @@ -53,12 +50,12 @@ public: return a.second > b.second; }); 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]; totalWeight += item.second; } 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]; boneIndices[i] = item.first; boneWeights[i] = item.second / totalWeight; diff --git a/src/riggenerator.cpp b/src/riggenerator.cpp index c92f3cb5..9b8ab68d 100644 --- a/src/riggenerator.cpp +++ b/src/riggenerator.cpp @@ -80,16 +80,16 @@ Object *RigGenerator::takeObject() return object; } -std::vector *RigGenerator::takeResultBones() +std::vector *RigGenerator::takeResultBones() { - std::vector *resultBones = m_resultBones; + std::vector *resultBones = m_resultBones; m_resultBones = nullptr; return resultBones; } -std::map *RigGenerator::takeResultWeights() +std::map *RigGenerator::takeResultWeights() { - std::map *resultWeights = m_resultWeights; + std::map *resultWeights = m_resultWeights; m_resultWeights = nullptr; return resultWeights; } @@ -408,12 +408,12 @@ void RigGenerator::buildSkeleton() m_rootSpineJointIndex = m_attachLimbsToSpineJointIndices[0]; m_lastSpineJointIndex = m_spineJoints.size() - 1; - m_resultBones = new std::vector; - m_resultWeights = new std::map; + m_resultBones = new std::vector; + m_resultWeights = new std::map; { const auto &firstSpineNode = m_object->nodes[m_spineJoints[m_rootSpineJointIndex]]; - RiggerBone bone; + RigBone bone; bone.headPosition = QVector3D(0.0, 0.0, 0.0); bone.tailPosition = firstSpineNode.origin; bone.headRadius = 0; @@ -432,7 +432,7 @@ void RigGenerator::buildSkeleton() ++spineJointIndex) { const auto ¤tNode = m_object->nodes[m_spineJoints[spineJointIndex]]; const auto &nextNode = m_object->nodes[m_spineJoints[spineJointIndex + 1]]; - RiggerBone bone; + RigBone bone; bone.headPosition = currentNode.origin; bone.tailPosition = nextNode.origin; bone.headRadius = currentNode.radius; @@ -454,7 +454,7 @@ void RigGenerator::buildSkeleton() const auto &spineNode = m_object->nodes[m_spineJoints[spineJointIndex]]; const auto &limbFirstNode = m_object->nodes[limbJoints[limbIndex][0]]; const auto &parentIndex = attachedBoneIndex(spineJointIndex); - RiggerBone bone; + RigBone bone; bone.headPosition = spineNode.origin; bone.tailPosition = limbFirstNode.origin; bone.headRadius = spineNode.radius; @@ -478,7 +478,7 @@ void RigGenerator::buildSkeleton() ++limbJointIndex) { const auto ¤tNode = m_object->nodes[joints[limbJointIndex]]; const auto &nextNode = m_object->nodes[joints[limbJointIndex + 1]]; - RiggerBone bone; + RigBone bone; bone.headPosition = currentNode.origin; bone.tailPosition = nextNode.origin; bone.headRadius = currentNode.radius; @@ -516,7 +516,7 @@ void RigGenerator::buildSkeleton() ++neckJointIndex) { const auto ¤tNode = m_object->nodes[m_neckJoints[neckJointIndex]]; const auto &nextNode = m_object->nodes[m_neckJoints[neckJointIndex + 1]]; - RiggerBone bone; + RigBone bone; bone.headPosition = currentNode.origin; bone.tailPosition = nextNode.origin; bone.headRadius = currentNode.radius; @@ -548,7 +548,7 @@ void RigGenerator::buildSkeleton() const auto &nextNode = spineJointIndex > 0 ? m_object->nodes[m_spineJoints[spineJointIndex - 1]] : m_object->nodes[m_tailJoints[0]]; - RiggerBone bone; + RigBone bone; bone.headPosition = currentNode.origin; bone.tailPosition = nextNode.origin; bone.headRadius = currentNode.radius; @@ -574,7 +574,7 @@ void RigGenerator::buildSkeleton() ++tailJointIndex) { const auto ¤tNode = m_object->nodes[m_tailJoints[tailJointIndex]]; const auto &nextNode = m_object->nodes[m_tailJoints[tailJointIndex + 1]]; - RiggerBone bone; + RigBone bone; bone.headPosition = currentNode.origin; bone.tailPosition = nextNode.origin; bone.headRadius = currentNode.radius; @@ -1190,17 +1190,17 @@ void RigGenerator::buildDemoMesh() const auto &resultWeights = *m_resultWeights; const auto &resultBones = *m_resultBones; - m_resultWeights = new std::map; + m_resultWeights = new std::map; *m_resultWeights = resultWeights; - m_resultBones = new std::vector; + m_resultBones = new std::vector; *m_resultBones = resultBones; for (const auto &weightItem: resultWeights) { size_t vertexIndex = weightItem.first; const auto &weight = weightItem.second; 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]; const auto &bone = resultBones[boneIndex]; blendR += bone.color.red() * weight.boneWeights[i]; diff --git a/src/riggenerator.h b/src/riggenerator.h index 1b06fe06..d800d1e9 100644 --- a/src/riggenerator.h +++ b/src/riggenerator.h @@ -6,7 +6,7 @@ #include #include "object.h" #include "model.h" -#include "rigger.h" +#include "rig.h" #include "rigtype.h" class RigGenerator : public QObject @@ -16,8 +16,8 @@ public: RigGenerator(RigType rigType, const Object &object); ~RigGenerator(); Model *takeResultMesh(); - std::vector *takeResultBones(); - std::map *takeResultWeights(); + std::vector *takeResultBones(); + std::map *takeResultWeights(); const std::vector> &messages(); Object *takeObject(); bool isSuccessful(); @@ -38,8 +38,8 @@ private: RigType m_rigType = RigType::None; Object *m_object = nullptr; Model *m_resultMesh = nullptr; - std::vector *m_resultBones = nullptr; - std::map *m_resultWeights = nullptr; + std::vector *m_resultBones = nullptr; + std::map *m_resultWeights = nullptr; std::vector> m_messages; std::map> m_neighborMap; std::vector m_boneNodeChain; diff --git a/src/rigxml.cpp b/src/rigxml.cpp new file mode 100644 index 00000000..c6b68f8b --- /dev/null +++ b/src/rigxml.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include "rigxml.h" +#include "util.h" +#include "jointnodetree.h" + +void saveRigToXmlStream(const Object *object, + const std::vector *rigBones, + const std::map *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(); +} diff --git a/src/rigxml.h b/src/rigxml.h new file mode 100644 index 00000000..907118d4 --- /dev/null +++ b/src/rigxml.h @@ -0,0 +1,12 @@ +#ifndef DUST3D_RIG_XML_H +#define DUST3D_RIG_XML_H +#include +#include "rig.h" +#include "object.h" + +void saveRigToXmlStream(const Object *object, + const std::vector *rigBones, + const std::map *rigWeights, + QXmlStreamWriter *writer); + +#endif diff --git a/src/skinnedmeshcreator.cpp b/src/skinnedmeshcreator.cpp index 9b798ca4..912d38a2 100644 --- a/src/skinnedmeshcreator.cpp +++ b/src/skinnedmeshcreator.cpp @@ -2,7 +2,7 @@ #include "theme.h" SkinnedMeshCreator::SkinnedMeshCreator(const Object &object, - const std::map &resultWeights) : + const std::map &resultWeights) : m_object(object), m_resultWeights(resultWeights) { @@ -48,7 +48,7 @@ Model *SkinnedMeshCreator::createMeshFromTransform(const std::vector QMatrix4x4 mixedMatrix; transformedPositions[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]; if (factor > 0) { transformedPositions[i][j] += matricies[weight.boneIndices[x]] * m_verticesBindPositions[i][j] * factor; diff --git a/src/skinnedmeshcreator.h b/src/skinnedmeshcreator.h index 77aa6f80..b098dc2b 100644 --- a/src/skinnedmeshcreator.h +++ b/src/skinnedmeshcreator.h @@ -12,11 +12,11 @@ class SkinnedMeshCreator { public: SkinnedMeshCreator(const Object &object, - const std::map &resultWeights); + const std::map &resultWeights); Model *createMeshFromTransform(const std::vector &matricies); private: Object m_object; - std::map m_resultWeights; + std::map m_resultWeights; std::vector> m_verticesOldIndices; std::vector> m_verticesBindPositions; std::vector> m_verticesBindNormals;