Avoid unnecessary mesh regeneration while only texture map changed

master
Jeremy Hu 2018-10-09 17:17:44 +08:00
parent 73d20da08f
commit 5f2a46be9c
10 changed files with 121 additions and 50 deletions

View File

@ -245,6 +245,9 @@ HEADERS += src/materialpreviewsgenerator.h
SOURCES += src/materialwidget.cpp SOURCES += src/materialwidget.cpp
HEADERS += src/materialwidget.h HEADERS += src/materialwidget.h
SOURCES += src/material.cpp
HEADERS += src/material.h
SOURCES += src/main.cpp SOURCES += src/main.cpp
HEADERS += src/version.h HEADERS += src/version.h

29
src/material.cpp Normal file
View File

@ -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;
}
}

21
src/material.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef MATERIAL_H
#define MATERIAL_H
#include <QImage>
#include <QUuid>
#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

View File

@ -12,6 +12,7 @@
#include "meshquadify.h" #include "meshquadify.h"
#include "meshweldseam.h" #include "meshweldseam.h"
#include "imageforever.h" #include "imageforever.h"
#include "material.h"
bool MeshGenerator::m_enableDebug = false; bool MeshGenerator::m_enableDebug = false;
PositionMap<int> *MeshGenerator::m_forMakePositionKey = new PositionMap<int>; PositionMap<int> *MeshGenerator::m_forMakePositionKey = new PositionMap<int>;
@ -257,27 +258,8 @@ void *MeshGenerator::combinePartMesh(QString partId)
materialId = QUuid(materialIdString); materialId = QUuid(materialIdString);
Material partMaterial; Material partMaterial;
for (const auto &material: m_snapshot->materials) { partMaterial.color = partColor;
if (materialIdString != valueOfKeyInMapOrEmpty(material.first, "id")) partMaterial.materialId = materialId;
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;
}
QString mirroredPartId; QString mirroredPartId;
QUuid mirroredPartIdNotAsString; QUuid mirroredPartIdNotAsString;

View File

@ -8,15 +8,10 @@
#include "positionmap.h" #include "positionmap.h"
#include "skeletonbonemark.h" #include "skeletonbonemark.h"
#include "texturetype.h" #include "texturetype.h"
#include "material.h"
#define MAX_WEIGHT_NUM 4 #define MAX_WEIGHT_NUM 4
struct Material
{
QColor color;
const QImage *textureImages[(int)TextureType::Count - 1] = {nullptr};
};
struct BmeshNode struct BmeshNode
{ {
QUuid partId; QUuid partId;

View File

@ -1524,26 +1524,11 @@ void SkeletonDocument::generateTexture()
m_isTextureObsolete = false; m_isTextureObsolete = false;
SkeletonSnapshot *snapshot = new SkeletonSnapshot;
toSnapshot(snapshot);
QThread *thread = new QThread; QThread *thread = new QThread;
m_textureGenerator = new TextureGenerator(*m_postProcessedResultContext); m_textureGenerator = new TextureGenerator(*m_postProcessedResultContext, snapshot);
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->moveToThread(thread); m_textureGenerator->moveToThread(thread);
connect(thread, &QThread::started, m_textureGenerator, &TextureGenerator::process); connect(thread, &QThread::started, m_textureGenerator, &TextureGenerator::process);
connect(m_textureGenerator, &TextureGenerator::finished, this, &SkeletonDocument::textureReady); 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.materialId = materialId;
part->second.dirty = true; part->second.dirty = true;
emit partMaterialIdChanged(partId); emit partMaterialIdChanged(partId);
emit skeletonChanged(); emit textureChanged();
} }
void SkeletonDocument::setPartRoundState(QUuid partId, bool rounded) void SkeletonDocument::setPartRoundState(QUuid partId, bool rounded)
@ -2887,6 +2872,7 @@ void SkeletonDocument::setMaterialLayers(QUuid materialId, std::vector<SkeletonM
findMaterialResult->second.layers = layers; findMaterialResult->second.layers = layers;
findMaterialResult->second.dirty = true; findMaterialResult->second.dirty = true;
emit materialLayersChanged(materialId); emit materialLayersChanged(materialId);
emit textureChanged();
emit optionsChanged(); emit optionsChanged();
} }

View File

@ -537,6 +537,7 @@ signals:
void meshGenerating(); void meshGenerating();
void postProcessing(); void postProcessing();
void textureGenerating(); void textureGenerating();
void textureChanged();
public: // need initialize public: // need initialize
float originX; float originX;
float originY; float originY;

View File

@ -815,6 +815,7 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
// m_document->postProcess(); // 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::postProcess);
connect(m_document, &SkeletonDocument::resultMeshChanged, m_document, &SkeletonDocument::generateRig); connect(m_document, &SkeletonDocument::resultMeshChanged, m_document, &SkeletonDocument::generateRig);
connect(m_document, &SkeletonDocument::rigChanged, m_document, &SkeletonDocument::generateRig); connect(m_document, &SkeletonDocument::rigChanged, m_document, &SkeletonDocument::generateRig);

View File

@ -2,12 +2,14 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QRegion> #include <QRegion>
#include <QPolygon> #include <QPolygon>
#include <QElapsedTimer>
#include "texturegenerator.h" #include "texturegenerator.h"
#include "theme.h" #include "theme.h"
#include "dust3dutil.h"
int TextureGenerator::m_textureSize = 1024; int TextureGenerator::m_textureSize = 1024;
TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext) : TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext, SkeletonSnapshot *snapshot) :
m_resultTextureGuideImage(nullptr), m_resultTextureGuideImage(nullptr),
m_resultTextureImage(nullptr), m_resultTextureImage(nullptr),
m_resultTextureBorderImage(nullptr), m_resultTextureBorderImage(nullptr),
@ -17,7 +19,8 @@ TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext) :
m_resultTextureRoughnessImage(nullptr), m_resultTextureRoughnessImage(nullptr),
m_resultTextureMetalnessImage(nullptr), m_resultTextureMetalnessImage(nullptr),
m_resultTextureAmbientOcclusionImage(nullptr), m_resultTextureAmbientOcclusionImage(nullptr),
m_resultMesh(nullptr) m_resultMesh(nullptr),
m_snapshot(snapshot)
{ {
m_resultContext = new MeshResultContext(); m_resultContext = new MeshResultContext();
*m_resultContext = meshResultContext; *m_resultContext = meshResultContext;
@ -36,6 +39,7 @@ TextureGenerator::~TextureGenerator()
delete m_resultTextureMetalnessImage; delete m_resultTextureMetalnessImage;
delete m_resultTextureAmbientOcclusionImage; delete m_resultTextureAmbientOcclusionImage;
delete m_resultMesh; delete m_resultMesh;
delete m_snapshot;
} }
QImage *TextureGenerator::takeResultTextureGuideImage() QImage *TextureGenerator::takeResultTextureGuideImage()
@ -130,8 +134,53 @@ QPainterPath TextureGenerator::expandedPainterPath(const QPainterPath &painterPa
return (stroker.createStroke(painterPath) + painterPath).simplified(); return (stroker.createStroke(painterPath) + painterPath).simplified();
} }
void TextureGenerator::prepare()
{
if (nullptr == m_snapshot)
return;
std::map<QUuid, QUuid> 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() void TextureGenerator::generate()
{ {
QElapsedTimer countTimeConsumed;
countTimeConsumed.start();
prepare();
bool hasNormalMap = false; bool hasNormalMap = false;
bool hasMetalnessMap = false; bool hasMetalnessMap = false;
bool hasRoughnessMap = false; bool hasRoughnessMap = false;
@ -350,6 +399,8 @@ void TextureGenerator::generate()
m_resultMesh->setHasRoughnessInImage(hasRoughnessMap); m_resultMesh->setHasRoughnessInImage(hasRoughnessMap);
m_resultMesh->setHasAmbientOcclusionInImage(hasAmbientOcclusionMap); m_resultMesh->setHasAmbientOcclusionInImage(hasAmbientOcclusionMap);
} }
qDebug() << "The texture[" << TextureGenerator::m_textureSize << "x" << TextureGenerator::m_textureSize << "] generation took" << countTimeConsumed.elapsed() << "milliseconds";
} }
void TextureGenerator::process() void TextureGenerator::process()

View File

@ -10,7 +10,7 @@ class TextureGenerator : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
TextureGenerator(const MeshResultContext &meshResultContext); TextureGenerator(const MeshResultContext &meshResultContext, SkeletonSnapshot *snapshot=nullptr);
~TextureGenerator(); ~TextureGenerator();
QImage *takeResultTextureGuideImage(); QImage *takeResultTextureGuideImage();
QImage *takeResultTextureImage(); QImage *takeResultTextureImage();
@ -32,6 +32,7 @@ public slots:
public: public:
static int m_textureSize; static int m_textureSize;
private: private:
void prepare();
QPainterPath expandedPainterPath(const QPainterPath &painterPath); QPainterPath expandedPainterPath(const QPainterPath &painterPath);
private: private:
MeshResultContext *m_resultContext; MeshResultContext *m_resultContext;
@ -50,6 +51,7 @@ private:
std::map<QUuid, QImage> m_partMetalnessTextureMap; std::map<QUuid, QImage> m_partMetalnessTextureMap;
std::map<QUuid, QImage> m_partRoughnessTextureMap; std::map<QUuid, QImage> m_partRoughnessTextureMap;
std::map<QUuid, QImage> m_partAmbientOcclusionTextureMap; std::map<QUuid, QImage> m_partAmbientOcclusionTextureMap;
SkeletonSnapshot *m_snapshot;
}; };
#endif #endif