Implement bone preview images generator

master
Jeremy HU 2022-12-03 23:01:11 +11:00
parent ef0fe2dcfe
commit 03f1440e7d
9 changed files with 171 additions and 4 deletions

View File

@ -2,6 +2,11 @@
#include <dust3d/mesh/smooth_normal.h> #include <dust3d/mesh/smooth_normal.h>
#include <dust3d/mesh/trim_vertices.h> #include <dust3d/mesh/trim_vertices.h>
std::map<dust3d::Uuid, std::unique_ptr<ModelMesh>>* BoneGenerator::takeBonePreviewMeshes()
{
return m_bonePreviewMeshes.release();
}
void BoneGenerator::process() void BoneGenerator::process()
{ {
generate(); generate();

View File

@ -4,10 +4,13 @@
#include "model_mesh.h" #include "model_mesh.h"
#include <QObject> #include <QObject>
#include <dust3d/rig/bone_generator.h> #include <dust3d/rig/bone_generator.h>
#include <map>
#include <memory> #include <memory>
class BoneGenerator : public QObject, public dust3d::BoneGenerator { class BoneGenerator : public QObject, public dust3d::BoneGenerator {
Q_OBJECT Q_OBJECT
public:
std::map<dust3d::Uuid, std::unique_ptr<ModelMesh>>* takeBonePreviewMeshes();
public slots: public slots:
void process(); void process();
signals: signals:

View File

@ -1,4 +1,5 @@
#include "document.h" #include "document.h"
#include "bone_generator.h"
#include "image_forever.h" #include "image_forever.h"
#include "mesh_generator.h" #include "mesh_generator.h"
#include "mesh_result_post_processor.h" #include "mesh_result_post_processor.h"
@ -2795,6 +2796,11 @@ bool Document::isTextureGenerating() const
return nullptr != m_textureGenerator; return nullptr != m_textureGenerator;
} }
bool Document::isBoneGenerating() const
{
return nullptr != m_boneGenerator;
}
void Document::copyNodes(std::set<dust3d::Uuid> nodeIdSet) const void Document::copyNodes(std::set<dust3d::Uuid> nodeIdSet) const
{ {
dust3d::Snapshot snapshot; dust3d::Snapshot snapshot;
@ -2865,7 +2871,7 @@ void Document::addBone(const dust3d::Uuid& boneId)
return; return;
Bone bone(boneId); Bone bone(boneId);
boneMap.emplace(boneId, bone); boneMap.emplace(boneId, std::move(bone));
boneIdList.push_back(boneId); boneIdList.push_back(boneId);
emit boneAdded(boneId); emit boneAdded(boneId);
emit boneIdListChanged(); emit boneIdListChanged();
@ -3018,3 +3024,66 @@ void Document::pickBoneNode(const dust3d::Uuid& nodeId)
stopBoneJointsPicking(); stopBoneJointsPicking();
} }
void Document::generateBone()
{
if (nullptr != m_boneGenerator) {
m_isResultBoneObsolete = true;
return;
}
m_isResultBoneObsolete = false;
emit boneGenerating();
// TODO:
QThread* thread = new QThread;
m_boneGenerator = std::make_unique<BoneGenerator>();
m_boneGenerator->moveToThread(thread);
connect(thread, &QThread::started, m_boneGenerator.get(), &BoneGenerator::process);
connect(m_boneGenerator.get(), &BoneGenerator::finished, this, &Document::boneReady);
connect(m_boneGenerator.get(), &BoneGenerator::finished, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
void Document::boneReady()
{
std::unique_ptr<std::map<dust3d::Uuid, std::unique_ptr<ModelMesh>>> bonePreviewMeshes;
bonePreviewMeshes.reset(m_boneGenerator->takeBonePreviewMeshes());
bool bonePreviewsChanged = bonePreviewMeshes && !bonePreviewMeshes->empty();
if (bonePreviewsChanged) {
for (auto& it : *bonePreviewMeshes) {
setBonePreviewMesh(it.first, std::move(it.second));
}
emit resultBonePreviewMeshesChanged();
}
// TODO:
m_boneGenerator.reset();
emit resultBoneChanged();
if (m_isResultBoneObsolete)
generateBone();
}
void Document::setBonePreviewMesh(const dust3d::Uuid& boneId, std::unique_ptr<ModelMesh> mesh)
{
Document::Bone* bone = (Document::Bone*)findBone(boneId);
if (nullptr == bone)
return;
bone->updatePreviewMesh(std::move(mesh));
emit bonePreviewMeshChanged(boneId);
}
void Document::setBonePreviewPixmap(const dust3d::Uuid& boneId, const QPixmap& pixmap)
{
Document::Bone* bone = (Document::Bone*)findBone(boneId);
if (nullptr == bone)
return;
bone->previewPixmap = pixmap;
emit bonePreviewPixmapChanged(boneId);
}

View File

@ -24,6 +24,7 @@
class UvMapGenerator; class UvMapGenerator;
class MeshGenerator; class MeshGenerator;
class MeshResultPostProcessor; class MeshResultPostProcessor;
class BoneGenerator;
class Document : public QObject { class Document : public QObject {
Q_OBJECT Q_OBJECT
@ -208,8 +209,14 @@ public:
std::vector<dust3d::Uuid> joints; std::vector<dust3d::Uuid> joints;
QString name; QString name;
QPixmap previewPixmap; QPixmap previewPixmap;
bool isPreviewMeshObsolete = false;
void updatePreviewMesh(std::unique_ptr<ModelMesh> mesh);
ModelMesh* takePreviewMesh() const;
Bone(const dust3d::Uuid& withId = dust3d::Uuid()); Bone(const dust3d::Uuid& withId = dust3d::Uuid());
private:
std::unique_ptr<ModelMesh> m_previewMesh;
}; };
signals: signals:
@ -218,6 +225,7 @@ signals:
void partPreviewChanged(dust3d::Uuid partId); void partPreviewChanged(dust3d::Uuid partId);
void resultMeshChanged(); void resultMeshChanged();
void resultComponentPreviewMeshesChanged(); void resultComponentPreviewMeshesChanged();
void resultBonePreviewMeshesChanged();
void turnaroundChanged(); void turnaroundChanged();
void editModeChanged(); void editModeChanged();
void resultTextureChanged(); void resultTextureChanged();
@ -288,9 +296,12 @@ signals:
void boneNodesChanged(const dust3d::Uuid& boneId); void boneNodesChanged(const dust3d::Uuid& boneId);
void boneJointsChanged(const dust3d::Uuid& boneId); void boneJointsChanged(const dust3d::Uuid& boneId);
void boneNameChanged(const dust3d::Uuid& boneId); void boneNameChanged(const dust3d::Uuid& boneId);
void bonePreviewMeshChanged(const dust3d::Uuid& boneId);
void bonePreviewPixmapChanged(const dust3d::Uuid& boneId); void bonePreviewPixmapChanged(const dust3d::Uuid& boneId);
void boneIdListChanged(); void boneIdListChanged();
void rigChanged(); void rigChanged();
void boneGenerating();
void resultBoneChanged();
public: // need initialize public: // need initialize
QImage* textureImage = nullptr; QImage* textureImage = nullptr;
@ -359,6 +370,7 @@ public:
bool isMeshGenerating() const; bool isMeshGenerating() const;
bool isPostProcessing() const; bool isPostProcessing() const;
bool isTextureGenerating() const; bool isTextureGenerating() const;
bool isBoneGenerating() const;
void collectCutFaceList(std::vector<QString>& cutFaces) const; void collectCutFaceList(std::vector<QString>& cutFaces) const;
float getOriginX(bool rotated = false) const float getOriginX(bool rotated = false) const
{ {
@ -417,6 +429,8 @@ public:
void resetDirtyFlags(); void resetDirtyFlags();
void markAllDirty(); void markAllDirty();
const Bone* findBone(const dust3d::Uuid& boneId) const; const Bone* findBone(const dust3d::Uuid& boneId) const;
void setBonePreviewMesh(const dust3d::Uuid& boneId, std::unique_ptr<ModelMesh> mesh);
void setBonePreviewPixmap(const dust3d::Uuid& boneId, const QPixmap& pixmap);
public slots: public slots:
void undo(); void undo();
@ -435,6 +449,8 @@ public slots:
void textureReady(); void textureReady();
void postProcess(); void postProcess();
void postProcessedMeshResultReady(); void postProcessedMeshResultReady();
void generateBone();
void boneReady();
void setPartSubdivState(dust3d::Uuid partId, bool subdived); void setPartSubdivState(dust3d::Uuid partId, bool subdived);
void setPartXmirrorState(dust3d::Uuid partId, bool mirrored); void setPartXmirrorState(dust3d::Uuid partId, bool mirrored);
void setPartDeformThickness(dust3d::Uuid partId, float thickness); void setPartDeformThickness(dust3d::Uuid partId, float thickness);
@ -565,10 +581,14 @@ private:
float m_originZ = 0; float m_originZ = 0;
dust3d::Uuid m_currentCanvasComponentId; dust3d::Uuid m_currentCanvasComponentId;
bool m_allPositionRelatedLocksEnabled = true; bool m_allPositionRelatedLocksEnabled = true;
dust3d::Uuid m_currentBondId; dust3d::Uuid m_currentBondId;
size_t m_currentBoneJoints = 0; size_t m_currentBoneJoints = 0;
std::vector<dust3d::Uuid> m_currentBoneJointNodes; std::vector<dust3d::Uuid> m_currentBoneJointNodes;
std::unique_ptr<BoneGenerator> m_boneGenerator;
bool m_isResultBoneObsolete = false;
private: private:
static unsigned long m_maxSnapshot; static unsigned long m_maxSnapshot;
std::deque<HistoryItem> m_undoItems; std::deque<HistoryItem> m_undoItems;

View File

@ -4,3 +4,16 @@ Document::Bone::Bone(const dust3d::Uuid& withId)
{ {
id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; id = withId.isNull() ? dust3d::Uuid::createUuid() : withId;
} }
void Document::Bone::updatePreviewMesh(std::unique_ptr<ModelMesh> mesh)
{
m_previewMesh = std::move(mesh);
isPreviewMeshObsolete = true;
}
ModelMesh* Document::Bone::takePreviewMesh() const
{
if (nullptr == m_previewMesh)
return nullptr;
return new ModelMesh(*m_previewMesh);
}

View File

@ -208,6 +208,9 @@ DocumentWindow::DocumentWindow()
connect(m_document, &Document::textureGenerating, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::textureGenerating, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::resultTextureChanged, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::resultTextureChanged, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::postProcessedResultChanged, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::postProcessedResultChanged, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::boneGenerating, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::resultBoneChanged, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::resultBonePreviewMeshesChanged, this, &DocumentWindow::generateBonePreviewImages);
toolButtonLayout->addWidget(addButton); toolButtonLayout->addWidget(addButton);
toolButtonLayout->addWidget(selectButton); toolButtonLayout->addWidget(selectButton);
@ -616,6 +619,8 @@ DocumentWindow::DocumentWindow()
connect(m_document, &Document::textureChanged, m_document, &Document::generateTexture); connect(m_document, &Document::textureChanged, m_document, &Document::generateTexture);
connect(m_document, &Document::resultMeshChanged, m_document, &Document::postProcess); connect(m_document, &Document::resultMeshChanged, m_document, &Document::postProcess);
connect(m_document, &Document::postProcessedResultChanged, m_document, &Document::generateTexture); connect(m_document, &Document::postProcessedResultChanged, m_document, &Document::generateTexture);
connect(m_document, &Document::rigChanged, m_document, &Document::generateBone);
connect(m_document, &Document::postProcessedResultChanged, m_document, &Document::generateBone);
connect(m_document, &Document::resultTextureChanged, [=]() { connect(m_document, &Document::resultTextureChanged, [=]() {
if (m_document->isMeshGenerating()) if (m_document->isMeshGenerating())
return; return;
@ -677,7 +682,7 @@ DocumentWindow::DocumentWindow()
void DocumentWindow::updateInprogressIndicator() void DocumentWindow::updateInprogressIndicator()
{ {
bool inprogress = m_document->isMeshGenerating() || m_document->isPostProcessing() || m_document->isTextureGenerating() || nullptr != m_componentPreviewImagesGenerator || nullptr != m_componentPreviewImagesDecorator; bool inprogress = m_document->isMeshGenerating() || m_document->isPostProcessing() || m_document->isTextureGenerating() || m_document->isBoneGenerating() || nullptr != m_componentPreviewImagesGenerator || nullptr != m_componentPreviewImagesDecorator;
if (inprogress == m_inprogressIndicator->isSpinning()) if (inprogress == m_inprogressIndicator->isSpinning())
return; return;
m_inprogressIndicator->showSpinner(inprogress); m_inprogressIndicator->showSpinner(inprogress);
@ -1403,3 +1408,52 @@ void DocumentWindow::toggleRenderColor()
mesh->removeColor(); mesh->removeColor();
m_modelRenderWidget->updateMesh(mesh); m_modelRenderWidget->updateMesh(mesh);
} }
void DocumentWindow::generateBonePreviewImages()
{
if (nullptr != m_bonePreviewImagesGenerator) {
m_isBonePreviewImagesObsolete = true;
return;
}
m_isBonePreviewImagesObsolete = false;
QThread* thread = new QThread;
m_bonePreviewImagesGenerator = new MeshPreviewImagesGenerator(new ModelOffscreenRender(m_modelRenderWidget->format()));
for (auto& bone : m_document->boneMap) {
if (!bone.second.isPreviewMeshObsolete)
continue;
bone.second.isPreviewMeshObsolete = false;
auto previewMesh = std::unique_ptr<ModelMesh>(bone.second.takePreviewMesh());
const bool useFrontView = false;
m_bonePreviewImagesGenerator->addInput(bone.first, std::move(previewMesh), useFrontView);
}
m_bonePreviewImagesGenerator->moveToThread(thread);
connect(thread, &QThread::started, m_bonePreviewImagesGenerator, &MeshPreviewImagesGenerator::process);
connect(m_bonePreviewImagesGenerator, &MeshPreviewImagesGenerator::finished, this, &DocumentWindow::bonePreviewImagesReady);
connect(m_bonePreviewImagesGenerator, &MeshPreviewImagesGenerator::finished, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
updateInprogressIndicator();
}
void DocumentWindow::bonePreviewImagesReady()
{
std::unique_ptr<std::map<dust3d::Uuid, QImage>> boneImages;
boneImages.reset(m_bonePreviewImagesGenerator->takeImages());
if (nullptr != boneImages) {
for (const auto& it : *boneImages) {
m_document->setBonePreviewPixmap(it.first, QPixmap::fromImage(it.second));
}
}
delete m_bonePreviewImagesGenerator;
m_bonePreviewImagesGenerator = nullptr;
if (m_isBonePreviewImagesObsolete)
generateBonePreviewImages();
else
updateInprogressIndicator();
}

View File

@ -90,6 +90,8 @@ public slots:
void componentPreviewImagesReady(); void componentPreviewImagesReady();
void decorateComponentPreviewImages(); void decorateComponentPreviewImages();
void componentPreviewImageDecorationsReady(); void componentPreviewImageDecorationsReady();
void generateBonePreviewImages();
void bonePreviewImagesReady();
void updateInprogressIndicator(); void updateInprogressIndicator();
void openRecentFile(); void openRecentFile();
void updateRecentFileActions(); void updateRecentFileActions();
@ -170,6 +172,9 @@ private:
std::unique_ptr<ComponentPreviewImagesDecorator> m_componentPreviewImagesDecorator; std::unique_ptr<ComponentPreviewImagesDecorator> m_componentPreviewImagesDecorator;
bool m_isComponentPreviewImageDecorationsObsolete = false; bool m_isComponentPreviewImageDecorationsObsolete = false;
MeshPreviewImagesGenerator* m_bonePreviewImagesGenerator = nullptr;
bool m_isBonePreviewImagesObsolete = false;
PartManageWidget* m_partManageWidget = nullptr; PartManageWidget* m_partManageWidget = nullptr;
BoneManageWidget* m_boneManageWidget = nullptr; BoneManageWidget* m_boneManageWidget = nullptr;

View File

@ -24,7 +24,6 @@
#include <dust3d/mesh/mesh_combiner.h> #include <dust3d/mesh/mesh_combiner.h>
#include <dust3d/mesh/solid_mesh_boolean_operation.h> #include <dust3d/mesh/solid_mesh_boolean_operation.h>
#include <dust3d/mesh/triangulate.h> #include <dust3d/mesh/triangulate.h>
#include <dust3d/util/obj.h>
namespace dust3d { namespace dust3d {

View File

@ -25,7 +25,6 @@
#include <dust3d/base/position_key.h> #include <dust3d/base/position_key.h>
#include <dust3d/mesh/re_triangulator.h> #include <dust3d/mesh/re_triangulator.h>
#include <dust3d/mesh/solid_mesh_boolean_operation.h> #include <dust3d/mesh/solid_mesh_boolean_operation.h>
#include <dust3d/util/obj.h>
#include <queue> #include <queue>
#include <set> #include <set>
#include <stdio.h> #include <stdio.h>