Add tile scale setting for texture generator

master
Jeremy Hu 2019-11-03 09:45:20 +09:30
parent 9a587fc895
commit 0abaa707f5
12 changed files with 106 additions and 40 deletions

View File

@ -791,6 +791,10 @@ Tips:
<source>Transparency</source> <source>Transparency</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Tile Scale</source>
<translation></translation>
</message>
</context> </context>
<context> <context>
<name>PoseEditWidget</name> <name>PoseEditWidget</name>

Binary file not shown.

View File

@ -1192,6 +1192,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
maps.push_back(textureMap); maps.push_back(textureMap);
} }
std::map<QString, QString> layerAttributes; std::map<QString, QString> layerAttributes;
if (!qFuzzyCompare((float)layer.tileScale, (float)1.0))
layerAttributes["tileScale"] = QString::number(layer.tileScale);
layers.push_back({layerAttributes, maps}); layers.push_back({layerAttributes, maps});
} }
snapshot->materials.push_back(std::make_pair(material, layers)); snapshot->materials.push_back(std::make_pair(material, layers));
@ -1300,6 +1302,9 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
oldNewIdMap[QUuid(valueOfKeyInMapOrEmpty(materialAttributes, "id"))] = newMaterialId; oldNewIdMap[QUuid(valueOfKeyInMapOrEmpty(materialAttributes, "id"))] = newMaterialId;
for (const auto &layerIt: materialIt.second) { for (const auto &layerIt: materialIt.second) {
MaterialLayer layer; MaterialLayer layer;
auto findTileScale = layerIt.first.find("tileScale");
if (findTileScale != layerIt.first.end())
layer.tileScale = findTileScale->second.toFloat();
for (const auto &mapItem: layerIt.second) { for (const auto &mapItem: layerIt.second) {
auto textureTypeString = valueOfKeyInMapOrEmpty(mapItem, "for"); auto textureTypeString = valueOfKeyInMapOrEmpty(mapItem, "for");
auto textureType = TextureTypeFromString(textureTypeString.toUtf8().constData()); auto textureType = TextureTypeFromString(textureTypeString.toUtf8().constData());

View File

@ -336,6 +336,7 @@ class MaterialLayer
{ {
public: public:
std::vector<MaterialMap> maps; std::vector<MaterialMap> maps;
float tileScale = 1.0;
}; };
class Material class Material

View File

@ -2,7 +2,10 @@
#include "imageforever.h" #include "imageforever.h"
#include "util.h" #include "util.h"
void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot, const QUuid &materialId, MaterialTextures &materialTextures) void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot,
const QUuid &materialId,
MaterialTextures &materialTextures,
float &tileScale)
{ {
QString materialIdString = materialId.toString(); QString materialIdString = materialId.toString();
for (const auto &materialItem: snapshot.materials) { for (const auto &materialItem: snapshot.materials) {
@ -10,6 +13,9 @@ void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot, const QUui
continue; continue;
for (const auto &layer: materialItem.second) { for (const auto &layer: materialItem.second) {
//FIXME: Only support one layer currently //FIXME: Only support one layer currently
auto findTileScale = layer.first.find("tileScale");
if (findTileScale != layer.first.end())
tileScale = findTileScale->second.toFloat();
for (const auto &mapItem: layer.second) { for (const auto &mapItem: layer.second) {
auto textureType = TextureTypeFromString(valueOfKeyInMapOrEmpty(mapItem, "for").toUtf8().constData()); auto textureType = TextureTypeFromString(valueOfKeyInMapOrEmpty(mapItem, "for").toUtf8().constData());
if (textureType != TextureType::None) { if (textureType != TextureType::None) {

View File

@ -10,6 +10,9 @@ struct MaterialTextures
const QImage *textureImages[(int)TextureType::Count - 1] = {nullptr}; const QImage *textureImages[(int)TextureType::Count - 1] = {nullptr};
}; };
void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot, const QUuid &materialId, MaterialTextures &materialTextures); void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot,
const QUuid &materialId,
MaterialTextures &materialTextures,
float &tileScale);
#endif #endif

View File

@ -121,6 +121,30 @@ MaterialEditWidget::MaterialEditWidget(const Document *document, QWidget *parent
QPushButton *saveButton = new QPushButton(tr("Save")); QPushButton *saveButton = new QPushButton(tr("Save"));
connect(saveButton, &QPushButton::clicked, this, &MaterialEditWidget::save); connect(saveButton, &QPushButton::clicked, this, &MaterialEditWidget::save);
saveButton->setDefault(true); saveButton->setDefault(true);
FloatNumberWidget *tileScaleWidget = new FloatNumberWidget;
tileScaleWidget->setItemName(tr("Tile Scale"));
tileScaleWidget->setRange(0.01, 1.0);
tileScaleWidget->setValue(m_layers[0].tileScale);
m_tileScaleSlider = tileScaleWidget;
connect(tileScaleWidget, &FloatNumberWidget::valueChanged, [=](float value) {
m_layers[0].tileScale = value;
emit layersAdjusted();
});
QPushButton *tileScaleEraser = new QPushButton(QChar(fa::eraser));
Theme::initAwesomeToolButton(tileScaleEraser);
connect(tileScaleEraser, &QPushButton::clicked, [=]() {
tileScaleWidget->setValue(1.0);
});
QHBoxLayout *tileScaleLayout = new QHBoxLayout;
tileScaleLayout->addWidget(tileScaleEraser);
tileScaleLayout->addWidget(tileScaleWidget);
tileScaleLayout->addStretch();
QHBoxLayout *baseInfoLayout = new QHBoxLayout; QHBoxLayout *baseInfoLayout = new QHBoxLayout;
baseInfoLayout->addWidget(new QLabel(tr("Name"))); baseInfoLayout->addWidget(new QLabel(tr("Name")));
@ -132,6 +156,7 @@ MaterialEditWidget::MaterialEditWidget(const Document *document, QWidget *parent
mainLayout->addLayout(paramtersLayout); mainLayout->addLayout(paramtersLayout);
mainLayout->addStretch(); mainLayout->addStretch();
mainLayout->addWidget(Theme::createHorizontalLineWidget()); mainLayout->addWidget(Theme::createHorizontalLineWidget());
mainLayout->addLayout(tileScaleLayout);
mainLayout->addLayout(baseInfoLayout); mainLayout->addLayout(baseInfoLayout);
setLayout(mainLayout); setLayout(mainLayout);
@ -273,6 +298,7 @@ void MaterialEditWidget::setEditMaterialLayers(std::vector<MaterialLayer> layers
} }
if (!layers.empty()) { if (!layers.empty()) {
for (const auto &layer: layers) { for (const auto &layer: layers) {
m_layers[0].tileScale = layer.tileScale;
for (const auto &mapItem: layer.maps) { for (const auto &mapItem: layer.maps) {
int index = (int)mapItem.forWhat - 1; int index = (int)mapItem.forWhat - 1;
if (index >= 0 && index < (int)TextureType::Count - 1) { if (index >= 0 && index < (int)TextureType::Count - 1) {
@ -280,6 +306,7 @@ void MaterialEditWidget::setEditMaterialLayers(std::vector<MaterialLayer> layers
} }
} }
} }
m_tileScaleSlider->setValue(m_layers[0].tileScale);
} }
for (int i = 1; i < (int)TextureType::Count; i++) { for (int i = 1; i < (int)TextureType::Count; i++) {
updateMapButtonBackground(m_textureMapButtons[i - 1], ImageForever::get(m_layers[0].maps[i - 1].imageId)); updateMapButtonBackground(m_textureMapButtons[i - 1], ImageForever::get(m_layers[0].maps[i - 1].imageId));

View File

@ -8,6 +8,7 @@
#include "modelwidget.h" #include "modelwidget.h"
#include "materialpreviewsgenerator.h" #include "materialpreviewsgenerator.h"
#include "imagepreviewwidget.h" #include "imagepreviewwidget.h"
#include "floatnumberwidget.h"
enum class PopupWidgetType enum class PopupWidgetType
{ {
@ -47,6 +48,7 @@ private:
const Document *m_document = nullptr; const Document *m_document = nullptr;
MaterialPreviewsGenerator *m_materialPreviewsGenerator = nullptr; MaterialPreviewsGenerator *m_materialPreviewsGenerator = nullptr;
ModelWidget *m_previewWidget = nullptr; ModelWidget *m_previewWidget = nullptr;
FloatNumberWidget *m_tileScaleSlider = nullptr;
bool m_isPreviewDirty = false; bool m_isPreviewDirty = false;
bool m_closed = false; bool m_closed = false;
QUuid m_materialId; QUuid m_materialId;

View File

@ -82,15 +82,15 @@ void MaterialPreviewsGenerator::generate()
continue; continue;
for (const auto &partId: partIds) { for (const auto &partId: partIds) {
if (TextureType::BaseColor == mapItem.forWhat) if (TextureType::BaseColor == mapItem.forWhat)
textureGenerator->addPartColorMap(partId, image); textureGenerator->addPartColorMap(partId, image, layer.tileScale);
else if (TextureType::Normal == mapItem.forWhat) else if (TextureType::Normal == mapItem.forWhat)
textureGenerator->addPartNormalMap(partId, image); textureGenerator->addPartNormalMap(partId, image, layer.tileScale);
else if (TextureType::Metalness == mapItem.forWhat) else if (TextureType::Metalness == mapItem.forWhat)
textureGenerator->addPartMetalnessMap(partId, image); textureGenerator->addPartMetalnessMap(partId, image, layer.tileScale);
else if (TextureType::Roughness == mapItem.forWhat) else if (TextureType::Roughness == mapItem.forWhat)
textureGenerator->addPartRoughnessMap(partId, image); textureGenerator->addPartRoughnessMap(partId, image, layer.tileScale);
else if (TextureType::AmbientOcclusion == mapItem.forWhat) else if (TextureType::AmbientOcclusion == mapItem.forWhat)
textureGenerator->addPartAmbientOcclusionMap(partId, image); textureGenerator->addPartAmbientOcclusionMap(partId, image, layer.tileScale);
} }
} }
} }

View File

@ -123,39 +123,39 @@ MeshLoader *TextureGenerator::takeResultMesh()
return resultMesh; return resultMesh;
} }
void TextureGenerator::addPartColorMap(QUuid partId, const QImage *image) void TextureGenerator::addPartColorMap(QUuid partId, const QImage *image, float tileScale)
{ {
if (nullptr == image) if (nullptr == image)
return; return;
m_partColorTextureMap[partId] = *image; m_partColorTextureMap[partId] = std::make_pair(*image, tileScale);
} }
void TextureGenerator::addPartNormalMap(QUuid partId, const QImage *image) void TextureGenerator::addPartNormalMap(QUuid partId, const QImage *image, float tileScale)
{ {
if (nullptr == image) if (nullptr == image)
return; return;
m_partNormalTextureMap[partId] = *image; m_partNormalTextureMap[partId] = std::make_pair(*image, tileScale);
} }
void TextureGenerator::addPartMetalnessMap(QUuid partId, const QImage *image) void TextureGenerator::addPartMetalnessMap(QUuid partId, const QImage *image, float tileScale)
{ {
if (nullptr == image) if (nullptr == image)
return; return;
m_partMetalnessTextureMap[partId] = *image; m_partMetalnessTextureMap[partId] = std::make_pair(*image, tileScale);
} }
void TextureGenerator::addPartRoughnessMap(QUuid partId, const QImage *image) void TextureGenerator::addPartRoughnessMap(QUuid partId, const QImage *image, float tileScale)
{ {
if (nullptr == image) if (nullptr == image)
return; return;
m_partRoughnessTextureMap[partId] = *image; m_partRoughnessTextureMap[partId] = std::make_pair(*image, tileScale);
} }
void TextureGenerator::addPartAmbientOcclusionMap(QUuid partId, const QImage *image) void TextureGenerator::addPartAmbientOcclusionMap(QUuid partId, const QImage *image, float tileScale)
{ {
if (nullptr == image) if (nullptr == image)
return; return;
m_partAmbientOcclusionTextureMap[partId] = *image; m_partAmbientOcclusionTextureMap[partId] = std::make_pair(*image, tileScale);
} }
QPainterPath TextureGenerator::expandedPainterPath(const QPainterPath &painterPath, int expandSize) QPainterPath TextureGenerator::expandedPainterPath(const QPainterPath &painterPath, int expandSize)
@ -188,19 +188,20 @@ void TextureGenerator::prepare()
auto findUpdatedMaterialIdResult = updatedMaterialIdMap.find(bmeshNode.mirrorFromPartId.isNull() ? bmeshNode.partId : bmeshNode.mirrorFromPartId); auto findUpdatedMaterialIdResult = updatedMaterialIdMap.find(bmeshNode.mirrorFromPartId.isNull() ? bmeshNode.partId : bmeshNode.mirrorFromPartId);
if (findUpdatedMaterialIdResult != updatedMaterialIdMap.end()) if (findUpdatedMaterialIdResult != updatedMaterialIdMap.end())
materialId = findUpdatedMaterialIdResult->second; materialId = findUpdatedMaterialIdResult->second;
initializeMaterialTexturesFromSnapshot(*m_snapshot, materialId, materialTextures); float tileScale = 1.0;
initializeMaterialTexturesFromSnapshot(*m_snapshot, materialId, materialTextures, tileScale);
const QImage *image = materialTextures.textureImages[i]; const QImage *image = materialTextures.textureImages[i];
if (nullptr != image) { if (nullptr != image) {
if (TextureType::BaseColor == forWhat) if (TextureType::BaseColor == forWhat)
addPartColorMap(bmeshNode.partId, image); addPartColorMap(bmeshNode.partId, image, tileScale);
else if (TextureType::Normal == forWhat) else if (TextureType::Normal == forWhat)
addPartNormalMap(bmeshNode.partId, image); addPartNormalMap(bmeshNode.partId, image, tileScale);
else if (TextureType::Metalness == forWhat) else if (TextureType::Metalness == forWhat)
addPartMetalnessMap(bmeshNode.partId, image); addPartMetalnessMap(bmeshNode.partId, image, tileScale);
else if (TextureType::Roughness == forWhat) else if (TextureType::Roughness == forWhat)
addPartRoughnessMap(bmeshNode.partId, image); addPartRoughnessMap(bmeshNode.partId, image, tileScale);
else if (TextureType::AmbientOcclusion == forWhat) else if (TextureType::AmbientOcclusion == forWhat)
addPartAmbientOcclusionMap(bmeshNode.partId, image); addPartAmbientOcclusionMap(bmeshNode.partId, image, tileScale);
} }
} }
} }
@ -395,13 +396,18 @@ void TextureGenerator::generate()
drawGradient(oppositeSource.first, std::get<0>(opposite->second), std::get<1>(opposite->second), std::get<2>(opposite->second), source.first); drawGradient(oppositeSource.first, std::get<0>(opposite->second), std::get<1>(opposite->second), std::get<2>(opposite->second), source.first);
} }
auto drawTexture = [&](const std::map<QUuid, QImage> &map, QPainter &painter) { auto drawTexture = [&](const std::map<QUuid, std::pair<QImage, float>> &map, QPainter &painter) {
for (const auto &it: partUvRects) { for (const auto &it: partUvRects) {
const auto &partId = it.first; const auto &partId = it.first;
const auto &rects = it.second; const auto &rects = it.second;
auto findTextureResult = map.find(partId); auto findTextureResult = map.find(partId);
if (findTextureResult != map.end()) { if (findTextureResult != map.end()) {
const auto &image = findTextureResult->second; float tileScale = findTextureResult->second.second;
const auto &image = findTextureResult->second.first;
auto newSize = image.size() * tileScale;
QImage scaledImage = image.scaled(newSize);
auto pixmap = QPixmap::fromImage(scaledImage);
QPixmap rotatedPixmap;
for (const auto &rect: rects) { for (const auto &rect: rects) {
QRectF translatedRect = { QRectF translatedRect = {
rect.left() * TextureGenerator::m_textureSize, rect.left() * TextureGenerator::m_textureSize,
@ -409,7 +415,19 @@ void TextureGenerator::generate()
rect.width() * TextureGenerator::m_textureSize, rect.width() * TextureGenerator::m_textureSize,
rect.height() * TextureGenerator::m_textureSize rect.height() * TextureGenerator::m_textureSize
}; };
painter.drawImage(translatedRect, image, QRectF(0, 0, image.width(), image.height())); if (translatedRect.width() < translatedRect.height()) {
if (rotatedPixmap.isNull()) {
QPoint center = scaledImage.rect().center();
QMatrix matrix;
matrix.translate(center.x(), center.y());
matrix.rotate(90);
auto rotatedImage = scaledImage.transformed(matrix);
rotatedPixmap = QPixmap::fromImage(rotatedImage);
}
painter.drawTiledPixmap(translatedRect, rotatedPixmap);
} else {
painter.drawTiledPixmap(translatedRect, pixmap);
}
} }
} }
} }

View File

@ -25,11 +25,11 @@ public:
QImage *takeResultTextureAmbientOcclusionImage(); QImage *takeResultTextureAmbientOcclusionImage();
Outcome *takeOutcome(); Outcome *takeOutcome();
MeshLoader *takeResultMesh(); MeshLoader *takeResultMesh();
void addPartColorMap(QUuid partId, const QImage *image); void addPartColorMap(QUuid partId, const QImage *image, float tileScale);
void addPartNormalMap(QUuid partId, const QImage *image); void addPartNormalMap(QUuid partId, const QImage *image, float tileScale);
void addPartMetalnessMap(QUuid partId, const QImage *image); void addPartMetalnessMap(QUuid partId, const QImage *image, float tileScale);
void addPartRoughnessMap(QUuid partId, const QImage *image); void addPartRoughnessMap(QUuid partId, const QImage *image, float tileScale);
void addPartAmbientOcclusionMap(QUuid partId, const QImage *image); void addPartAmbientOcclusionMap(QUuid partId, const QImage *image, float tileScale);
void generate(); void generate();
signals: signals:
void finished(); void finished();
@ -53,11 +53,11 @@ private:
QImage *m_resultTextureMetalnessImage; QImage *m_resultTextureMetalnessImage;
QImage *m_resultTextureAmbientOcclusionImage; QImage *m_resultTextureAmbientOcclusionImage;
MeshLoader *m_resultMesh; MeshLoader *m_resultMesh;
std::map<QUuid, QImage> m_partColorTextureMap; std::map<QUuid, std::pair<QImage, float>> m_partColorTextureMap;
std::map<QUuid, QImage> m_partNormalTextureMap; std::map<QUuid, std::pair<QImage, float>> m_partNormalTextureMap;
std::map<QUuid, QImage> m_partMetalnessTextureMap; std::map<QUuid, std::pair<QImage, float>> m_partMetalnessTextureMap;
std::map<QUuid, QImage> m_partRoughnessTextureMap; std::map<QUuid, std::pair<QImage, float>> m_partRoughnessTextureMap;
std::map<QUuid, QImage> m_partAmbientOcclusionTextureMap; std::map<QUuid, std::pair<QImage, float>> m_partAmbientOcclusionTextureMap;
Snapshot *m_snapshot; Snapshot *m_snapshot;
}; };

View File

@ -57,10 +57,10 @@ void Theme::initAwsomeBaseSizes()
Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67); Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67);
Theme::partPreviewImageSize = (Theme::miniIconSize * 3); Theme::partPreviewImageSize = (Theme::miniIconSize * 3);
Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 3.7; Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 3.7;
Theme::materialPreviewImageSize = Theme::sidebarPreferredWidth * 0.4; Theme::posePreviewImageSize = Theme::sidebarPreferredWidth * 0.4;
Theme::cutFacePreviewImageSize = Theme::materialPreviewImageSize; Theme::materialPreviewImageSize = Theme::posePreviewImageSize;
Theme::posePreviewImageSize = Theme::materialPreviewImageSize; Theme::cutFacePreviewImageSize = Theme::posePreviewImageSize;
Theme::motionPreviewImageSize = Theme::materialPreviewImageSize; Theme::motionPreviewImageSize = Theme::posePreviewImageSize;
Theme::normalButtonSize = Theme::toolIconSize * 2; Theme::normalButtonSize = Theme::toolIconSize * 2;
} }