From 5f2a46be9cf2867d5beac4c687a5f7a24ff638f9 Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Tue, 9 Oct 2018 17:17:44 +0800 Subject: [PATCH] Avoid unnecessary mesh regeneration while only texture map changed --- dust3d.pro | 3 ++ src/material.cpp | 29 ++++++++++++++++++ src/material.h | 21 +++++++++++++ src/meshgenerator.cpp | 24 ++------------- src/meshresultcontext.h | 7 +---- src/skeletondocument.cpp | 26 ++++------------ src/skeletondocument.h | 1 + src/skeletondocumentwindow.cpp | 1 + src/texturegenerator.cpp | 55 ++++++++++++++++++++++++++++++++-- src/texturegenerator.h | 4 ++- 10 files changed, 121 insertions(+), 50 deletions(-) create mode 100644 src/material.cpp create mode 100644 src/material.h diff --git a/dust3d.pro b/dust3d.pro index c4fc6ba1..700144fc 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -245,6 +245,9 @@ HEADERS += src/materialpreviewsgenerator.h SOURCES += src/materialwidget.cpp HEADERS += src/materialwidget.h +SOURCES += src/material.cpp +HEADERS += src/material.h + SOURCES += src/main.cpp HEADERS += src/version.h diff --git a/src/material.cpp b/src/material.cpp new file mode 100644 index 00000000..111e5975 --- /dev/null +++ b/src/material.cpp @@ -0,0 +1,29 @@ +#include "material.h" +#include "imageforever.h" +#include "dust3dutil.h" + +void initializeMaterialTexturesFromSnapshot(const SkeletonSnapshot &snapshot, const QUuid &materialId, MaterialTextures &materialTextures) +{ + QString materialIdString = materialId.toString(); + for (const auto &materialItem: snapshot.materials) { + if (materialIdString != valueOfKeyInMapOrEmpty(materialItem.first, "id")) + continue; + for (const auto &layer: materialItem.second) { + //FIXME: Only support one layer currently + for (const auto &mapItem: layer.second) { + auto textureType = TextureTypeFromString(valueOfKeyInMapOrEmpty(mapItem, "for").toUtf8().constData()); + if (textureType != TextureType::None) { + int index = (int)textureType - 1; + if (index >= 0 && index < (int)TextureType::Count - 1) { + if ("imageId" == valueOfKeyInMapOrEmpty(mapItem, "linkDataType")) { + auto imageIdString = valueOfKeyInMapOrEmpty(mapItem, "linkData"); + materialTextures.textureImages[index] = ImageForever::get(QUuid(imageIdString)); + } + } + } + } + break; + } + break; + } +} diff --git a/src/material.h b/src/material.h new file mode 100644 index 00000000..00590f2a --- /dev/null +++ b/src/material.h @@ -0,0 +1,21 @@ +#ifndef MATERIAL_H +#define MATERIAL_H +#include +#include +#include "texturetype.h" +#include "skeletonsnapshot.h" + +struct Material +{ + QColor color; + QUuid materialId; +}; + +struct MaterialTextures +{ + const QImage *textureImages[(int)TextureType::Count - 1] = {nullptr}; +}; + +void initializeMaterialTexturesFromSnapshot(const SkeletonSnapshot &snapshot, const QUuid &materialId, MaterialTextures &materialTextures); + +#endif diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index b968c0db..adab8f82 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -12,6 +12,7 @@ #include "meshquadify.h" #include "meshweldseam.h" #include "imageforever.h" +#include "material.h" bool MeshGenerator::m_enableDebug = false; PositionMap *MeshGenerator::m_forMakePositionKey = new PositionMap; @@ -257,27 +258,8 @@ void *MeshGenerator::combinePartMesh(QString partId) materialId = QUuid(materialIdString); Material partMaterial; - for (const auto &material: m_snapshot->materials) { - if (materialIdString != valueOfKeyInMapOrEmpty(material.first, "id")) - continue; - for (const auto &layer: material.second) { - //FIXME: Only support one layer currently - for (const auto &mapItem: layer.second) { - auto textureType = TextureTypeFromString(valueOfKeyInMapOrEmpty(mapItem, "for").toUtf8().constData()); - if (textureType != TextureType::None) { - int index = (int)textureType - 1; - if (index >= 0 && index < (int)TextureType::Count - 1) { - if ("imageId" == valueOfKeyInMapOrEmpty(mapItem, "linkDataType")) { - auto imageIdString = valueOfKeyInMapOrEmpty(mapItem, "linkData"); - partMaterial.textureImages[index] = ImageForever::get(QUuid(imageIdString)); - } - } - } - } - break; - } - break; - } + partMaterial.color = partColor; + partMaterial.materialId = materialId; QString mirroredPartId; QUuid mirroredPartIdNotAsString; diff --git a/src/meshresultcontext.h b/src/meshresultcontext.h index ad84e3f8..ff77aed3 100644 --- a/src/meshresultcontext.h +++ b/src/meshresultcontext.h @@ -8,15 +8,10 @@ #include "positionmap.h" #include "skeletonbonemark.h" #include "texturetype.h" +#include "material.h" #define MAX_WEIGHT_NUM 4 -struct Material -{ - QColor color; - const QImage *textureImages[(int)TextureType::Count - 1] = {nullptr}; -}; - struct BmeshNode { QUuid partId; diff --git a/src/skeletondocument.cpp b/src/skeletondocument.cpp index ff114b3e..c455aa82 100644 --- a/src/skeletondocument.cpp +++ b/src/skeletondocument.cpp @@ -1524,26 +1524,11 @@ void SkeletonDocument::generateTexture() m_isTextureObsolete = false; + SkeletonSnapshot *snapshot = new SkeletonSnapshot; + toSnapshot(snapshot); + QThread *thread = new QThread; - m_textureGenerator = new TextureGenerator(*m_postProcessedResultContext); - for (const auto &bmeshNode: m_postProcessedResultContext->bmeshNodes) { - for (size_t i = 0; i < sizeof(bmeshNode.material.textureImages) / sizeof(bmeshNode.material.textureImages[0]); ++i) { - TextureType forWhat = (TextureType)(i + 1); - const QImage *image = bmeshNode.material.textureImages[i]; - if (nullptr != image) { - if (TextureType::BaseColor == forWhat) - m_textureGenerator->addPartColorMap(bmeshNode.partId, image); - else if (TextureType::Normal == forWhat) - m_textureGenerator->addPartNormalMap(bmeshNode.partId, image); - else if (TextureType::Metalness == forWhat) - m_textureGenerator->addPartMetalnessMap(bmeshNode.partId, image); - else if (TextureType::Roughness == forWhat) - m_textureGenerator->addPartRoughnessMap(bmeshNode.partId, image); - else if (TextureType::AmbientOcclusion == forWhat) - m_textureGenerator->addPartAmbientOcclusionMap(bmeshNode.partId, image); - } - } - } + m_textureGenerator = new TextureGenerator(*m_postProcessedResultContext, snapshot); m_textureGenerator->moveToThread(thread); connect(thread, &QThread::started, m_textureGenerator, &TextureGenerator::process); connect(m_textureGenerator, &TextureGenerator::finished, this, &SkeletonDocument::textureReady); @@ -2270,7 +2255,7 @@ void SkeletonDocument::setPartMaterialId(QUuid partId, QUuid materialId) part->second.materialId = materialId; part->second.dirty = true; emit partMaterialIdChanged(partId); - emit skeletonChanged(); + emit textureChanged(); } void SkeletonDocument::setPartRoundState(QUuid partId, bool rounded) @@ -2887,6 +2872,7 @@ void SkeletonDocument::setMaterialLayers(QUuid materialId, std::vectorsecond.layers = layers; findMaterialResult->second.dirty = true; emit materialLayersChanged(materialId); + emit textureChanged(); emit optionsChanged(); } diff --git a/src/skeletondocument.h b/src/skeletondocument.h index 90110bbe..9f91b818 100644 --- a/src/skeletondocument.h +++ b/src/skeletondocument.h @@ -537,6 +537,7 @@ signals: void meshGenerating(); void postProcessing(); void textureGenerating(); + void textureChanged(); public: // need initialize float originX; float originY; diff --git a/src/skeletondocumentwindow.cpp b/src/skeletondocumentwindow.cpp index 9ee81d06..3dd7f971 100644 --- a/src/skeletondocumentwindow.cpp +++ b/src/skeletondocumentwindow.cpp @@ -815,6 +815,7 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : // m_document->postProcess(); // } //}); + connect(m_document, &SkeletonDocument::textureChanged, m_document, &SkeletonDocument::generateTexture); connect(m_document, &SkeletonDocument::resultMeshChanged, m_document, &SkeletonDocument::postProcess); connect(m_document, &SkeletonDocument::resultMeshChanged, m_document, &SkeletonDocument::generateRig); connect(m_document, &SkeletonDocument::rigChanged, m_document, &SkeletonDocument::generateRig); diff --git a/src/texturegenerator.cpp b/src/texturegenerator.cpp index 912fc5b7..f4fec217 100644 --- a/src/texturegenerator.cpp +++ b/src/texturegenerator.cpp @@ -2,12 +2,14 @@ #include #include #include +#include #include "texturegenerator.h" #include "theme.h" +#include "dust3dutil.h" int TextureGenerator::m_textureSize = 1024; -TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext) : +TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext, SkeletonSnapshot *snapshot) : m_resultTextureGuideImage(nullptr), m_resultTextureImage(nullptr), m_resultTextureBorderImage(nullptr), @@ -17,7 +19,8 @@ TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext) : m_resultTextureRoughnessImage(nullptr), m_resultTextureMetalnessImage(nullptr), m_resultTextureAmbientOcclusionImage(nullptr), - m_resultMesh(nullptr) + m_resultMesh(nullptr), + m_snapshot(snapshot) { m_resultContext = new MeshResultContext(); *m_resultContext = meshResultContext; @@ -36,6 +39,7 @@ TextureGenerator::~TextureGenerator() delete m_resultTextureMetalnessImage; delete m_resultTextureAmbientOcclusionImage; delete m_resultMesh; + delete m_snapshot; } QImage *TextureGenerator::takeResultTextureGuideImage() @@ -130,8 +134,53 @@ QPainterPath TextureGenerator::expandedPainterPath(const QPainterPath &painterPa return (stroker.createStroke(painterPath) + painterPath).simplified(); } +void TextureGenerator::prepare() +{ + if (nullptr == m_snapshot) + return; + + std::map updatedMaterialIdMap; + for (const auto &partIt: m_snapshot->parts) { + auto materialIdIt = partIt.second.find("materialId"); + if (materialIdIt == partIt.second.end()) + continue; + QUuid partId = QUuid(partIt.first); + QUuid materialId = QUuid(materialIdIt->second); + updatedMaterialIdMap.insert({partId, materialId}); + } + for (const auto &bmeshNode: m_resultContext->bmeshNodes) { + for (size_t i = 0; i < (int)TextureType::Count - 1; ++i) { + TextureType forWhat = (TextureType)(i + 1); + MaterialTextures materialTextures; + QUuid materialId = bmeshNode.material.materialId; + auto findUpdatedMaterialIdResult = updatedMaterialIdMap.find(bmeshNode.partId); + if (findUpdatedMaterialIdResult != updatedMaterialIdMap.end()) + materialId = findUpdatedMaterialIdResult->second; + initializeMaterialTexturesFromSnapshot(*m_snapshot, materialId, materialTextures); + const QImage *image = materialTextures.textureImages[i]; + if (nullptr != image) { + if (TextureType::BaseColor == forWhat) + addPartColorMap(bmeshNode.partId, image); + else if (TextureType::Normal == forWhat) + addPartNormalMap(bmeshNode.partId, image); + else if (TextureType::Metalness == forWhat) + addPartMetalnessMap(bmeshNode.partId, image); + else if (TextureType::Roughness == forWhat) + addPartRoughnessMap(bmeshNode.partId, image); + else if (TextureType::AmbientOcclusion == forWhat) + addPartAmbientOcclusionMap(bmeshNode.partId, image); + } + } + } +} + void TextureGenerator::generate() { + QElapsedTimer countTimeConsumed; + countTimeConsumed.start(); + + prepare(); + bool hasNormalMap = false; bool hasMetalnessMap = false; bool hasRoughnessMap = false; @@ -350,6 +399,8 @@ void TextureGenerator::generate() m_resultMesh->setHasRoughnessInImage(hasRoughnessMap); m_resultMesh->setHasAmbientOcclusionInImage(hasAmbientOcclusionMap); } + + qDebug() << "The texture[" << TextureGenerator::m_textureSize << "x" << TextureGenerator::m_textureSize << "] generation took" << countTimeConsumed.elapsed() << "milliseconds"; } void TextureGenerator::process() diff --git a/src/texturegenerator.h b/src/texturegenerator.h index 811f859e..65198f72 100644 --- a/src/texturegenerator.h +++ b/src/texturegenerator.h @@ -10,7 +10,7 @@ class TextureGenerator : public QObject { Q_OBJECT public: - TextureGenerator(const MeshResultContext &meshResultContext); + TextureGenerator(const MeshResultContext &meshResultContext, SkeletonSnapshot *snapshot=nullptr); ~TextureGenerator(); QImage *takeResultTextureGuideImage(); QImage *takeResultTextureImage(); @@ -32,6 +32,7 @@ public slots: public: static int m_textureSize; private: + void prepare(); QPainterPath expandedPainterPath(const QPainterPath &painterPath); private: MeshResultContext *m_resultContext; @@ -50,6 +51,7 @@ private: std::map m_partMetalnessTextureMap; std::map m_partRoughnessTextureMap; std::map m_partAmbientOcclusionTextureMap; + SkeletonSnapshot *m_snapshot; }; #endif