2022-10-25 11:31:44 +00:00
|
|
|
#include "uv_map_generator.h"
|
|
|
|
#include "image_forever.h"
|
2022-10-28 23:30:22 +00:00
|
|
|
#include <QMatrix>
|
|
|
|
#include <QPainter>
|
2022-10-25 11:31:44 +00:00
|
|
|
#include <dust3d/uv/uv_map_packer.h>
|
2022-11-01 12:10:21 +00:00
|
|
|
#include <unordered_set>
|
2022-10-25 11:31:44 +00:00
|
|
|
|
2022-10-30 08:08:03 +00:00
|
|
|
size_t UvMapGenerator::m_textureSize = 4096;
|
2022-10-28 23:30:22 +00:00
|
|
|
|
2022-10-25 11:31:44 +00:00
|
|
|
UvMapGenerator::UvMapGenerator(std::unique_ptr<dust3d::Object> object, std::unique_ptr<dust3d::Snapshot> snapshot)
|
|
|
|
: m_object(std::move(object))
|
|
|
|
, m_snapshot(std::move(snapshot))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void UvMapGenerator::process()
|
|
|
|
{
|
|
|
|
generate();
|
|
|
|
emit finished();
|
|
|
|
}
|
|
|
|
|
2022-10-28 23:30:22 +00:00
|
|
|
std::unique_ptr<QImage> UvMapGenerator::takeResultTextureColorImage()
|
|
|
|
{
|
|
|
|
return std::move(m_textureColorImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<QImage> UvMapGenerator::takeResultTextureNormalImage()
|
|
|
|
{
|
|
|
|
return std::move(m_textureNormalImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<QImage> UvMapGenerator::takeResultTextureRoughnessImage()
|
|
|
|
{
|
|
|
|
return std::move(m_textureRoughnessImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<QImage> UvMapGenerator::takeResultTextureMetalnessImage()
|
|
|
|
{
|
|
|
|
return std::move(m_textureMetalnessImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<QImage> UvMapGenerator::takeResultTextureAmbientOcclusionImage()
|
|
|
|
{
|
|
|
|
return std::move(m_textureAmbientOcclusionImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<ModelMesh> UvMapGenerator::takeResultMesh()
|
|
|
|
{
|
|
|
|
return std::move(m_mesh);
|
|
|
|
}
|
|
|
|
|
2022-10-25 11:31:44 +00:00
|
|
|
std::unique_ptr<dust3d::Object> UvMapGenerator::takeObject()
|
|
|
|
{
|
|
|
|
return std::move(m_object);
|
|
|
|
}
|
|
|
|
|
2022-10-28 23:30:22 +00:00
|
|
|
bool UvMapGenerator::hasTransparencySettings() const
|
|
|
|
{
|
|
|
|
return m_hasTransparencySettings;
|
|
|
|
}
|
|
|
|
|
2022-10-29 23:05:55 +00:00
|
|
|
QImage* UvMapGenerator::combineMetalnessRoughnessAmbientOcclusionImages(QImage* metalnessImage,
|
|
|
|
QImage* roughnessImage,
|
|
|
|
QImage* ambientOcclusionImage)
|
2022-10-25 11:31:44 +00:00
|
|
|
{
|
2022-10-29 23:05:55 +00:00
|
|
|
QImage* textureMetalnessRoughnessAmbientOcclusionImage = nullptr;
|
|
|
|
if (nullptr != metalnessImage || nullptr != roughnessImage || nullptr != ambientOcclusionImage) {
|
|
|
|
int textureSize = 0;
|
|
|
|
if (nullptr != metalnessImage)
|
|
|
|
textureSize = metalnessImage->height();
|
|
|
|
if (nullptr != roughnessImage)
|
|
|
|
textureSize = roughnessImage->height();
|
|
|
|
if (nullptr != ambientOcclusionImage)
|
|
|
|
textureSize = ambientOcclusionImage->height();
|
|
|
|
if (textureSize > 0) {
|
|
|
|
textureMetalnessRoughnessAmbientOcclusionImage = new QImage(textureSize, textureSize, QImage::Format_ARGB32);
|
|
|
|
textureMetalnessRoughnessAmbientOcclusionImage->fill(QColor(255, 255, 0));
|
|
|
|
for (int row = 0; row < textureMetalnessRoughnessAmbientOcclusionImage->height(); ++row) {
|
|
|
|
for (int col = 0; col < textureMetalnessRoughnessAmbientOcclusionImage->width(); ++col) {
|
|
|
|
QColor color(255, 255, 0);
|
|
|
|
if (nullptr != metalnessImage)
|
|
|
|
color.setBlue(qGray(metalnessImage->pixel(col, row)));
|
|
|
|
if (nullptr != roughnessImage)
|
|
|
|
color.setGreen(qGray(roughnessImage->pixel(col, row)));
|
|
|
|
if (nullptr != ambientOcclusionImage)
|
|
|
|
color.setRed(qGray(ambientOcclusionImage->pixel(col, row)));
|
|
|
|
textureMetalnessRoughnessAmbientOcclusionImage->setPixelColor(col, row, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return textureMetalnessRoughnessAmbientOcclusionImage;
|
|
|
|
}
|
2022-10-25 11:31:44 +00:00
|
|
|
|
2022-10-29 23:05:55 +00:00
|
|
|
void UvMapGenerator::packUvs()
|
|
|
|
{
|
2022-10-25 11:31:44 +00:00
|
|
|
m_mapPacker = std::make_unique<dust3d::UvMapPacker>();
|
|
|
|
|
|
|
|
for (const auto& partIt : m_snapshot->parts) {
|
|
|
|
const auto& colorImageIdIt = partIt.second.find("colorImageId");
|
|
|
|
if (colorImageIdIt == partIt.second.end())
|
|
|
|
continue;
|
|
|
|
auto imageId = dust3d::Uuid(colorImageIdIt->second);
|
|
|
|
const QImage* image = ImageForever::get(imageId);
|
|
|
|
if (nullptr == image)
|
|
|
|
continue;
|
|
|
|
const auto& findUvs = m_object->partTriangleUvs.find(dust3d::Uuid(partIt.first));
|
|
|
|
if (findUvs == m_object->partTriangleUvs.end())
|
|
|
|
continue;
|
|
|
|
dust3d::UvMapPacker::Part part;
|
|
|
|
part.id = imageId;
|
|
|
|
part.width = image->width();
|
|
|
|
part.height = image->height();
|
|
|
|
part.localUv = findUvs->second;
|
|
|
|
m_mapPacker->addPart(part);
|
|
|
|
}
|
|
|
|
|
2022-11-02 10:02:45 +00:00
|
|
|
m_mapPacker->addSeams(m_object->seamTriangleUvs);
|
2022-10-25 11:31:44 +00:00
|
|
|
|
2022-11-02 10:02:45 +00:00
|
|
|
m_mapPacker->pack();
|
2022-11-01 12:10:21 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 23:05:55 +00:00
|
|
|
void UvMapGenerator::generateTextureColorImage()
|
|
|
|
{
|
2022-10-28 23:30:22 +00:00
|
|
|
m_textureColorImage = std::make_unique<QImage>(UvMapGenerator::m_textureSize, UvMapGenerator::m_textureSize, QImage::Format_ARGB32);
|
|
|
|
m_textureColorImage->fill(Qt::white);
|
|
|
|
|
|
|
|
QPainter colorTexturePainter;
|
|
|
|
colorTexturePainter.begin(m_textureColorImage.get());
|
|
|
|
colorTexturePainter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
colorTexturePainter.setRenderHint(QPainter::HighQualityAntialiasing);
|
|
|
|
colorTexturePainter.setPen(Qt::NoPen);
|
|
|
|
|
|
|
|
for (const auto& layout : m_mapPacker->packedLayouts()) {
|
2022-11-02 21:22:12 +00:00
|
|
|
const QImage* image = image = ImageForever::get(layout.id);
|
|
|
|
if (nullptr == image) {
|
|
|
|
dust3dDebug << "Find image failed:" << layout.id.toString();
|
|
|
|
continue;
|
2022-10-29 23:05:55 +00:00
|
|
|
}
|
2022-10-28 23:30:22 +00:00
|
|
|
QPixmap brushPixmap;
|
|
|
|
if (layout.flipped) {
|
|
|
|
auto scaledImage = image->scaled(QSize(layout.height * UvMapGenerator::m_textureSize,
|
|
|
|
layout.width * UvMapGenerator::m_textureSize));
|
|
|
|
QPoint center = scaledImage.rect().center();
|
|
|
|
QMatrix matrix;
|
|
|
|
matrix.translate(center.x(), center.y());
|
|
|
|
matrix.rotate(90);
|
|
|
|
auto rotatedImage = scaledImage.transformed(matrix).mirrored(true, false);
|
|
|
|
brushPixmap = QPixmap::fromImage(rotatedImage);
|
|
|
|
} else {
|
|
|
|
auto scaledImage = image->scaled(QSize(layout.width * UvMapGenerator::m_textureSize,
|
|
|
|
layout.height * UvMapGenerator::m_textureSize));
|
|
|
|
brushPixmap = QPixmap::fromImage(scaledImage);
|
|
|
|
}
|
|
|
|
colorTexturePainter.drawPixmap(layout.left * UvMapGenerator::m_textureSize,
|
|
|
|
layout.top * UvMapGenerator::m_textureSize,
|
|
|
|
brushPixmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
colorTexturePainter.end();
|
|
|
|
}
|
|
|
|
|
2022-10-29 23:05:55 +00:00
|
|
|
void UvMapGenerator::generateUvCoords()
|
2022-10-28 23:30:22 +00:00
|
|
|
{
|
2022-10-29 23:05:55 +00:00
|
|
|
std::map<std::array<dust3d::PositionKey, 3>, std::array<dust3d::Vector2, 3>> mergedUvs;
|
|
|
|
for (const auto& layout : m_mapPacker->packedLayouts()) {
|
|
|
|
for (const auto& it : layout.globalUv) {
|
|
|
|
mergedUvs.insert({ it.first, it.second });
|
2022-10-28 23:30:22 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-29 23:05:55 +00:00
|
|
|
std::vector<std::vector<dust3d::Vector2>> triangleUvs(m_object->triangles.size(), std::vector<dust3d::Vector2> { dust3d::Vector2(0.0, 0.0), dust3d::Vector2(0.0, 0.0), dust3d::Vector2(0.0, 0.0) });
|
|
|
|
for (size_t n = 0; n < m_object->triangles.size(); ++n) {
|
|
|
|
const auto& triangle = m_object->triangles[n];
|
|
|
|
auto findUvs = mergedUvs.find({ dust3d::PositionKey(m_object->vertices[triangle[0]]),
|
|
|
|
dust3d::PositionKey(m_object->vertices[triangle[1]]),
|
|
|
|
dust3d::PositionKey(m_object->vertices[triangle[2]]) });
|
|
|
|
if (findUvs == mergedUvs.end()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
triangleUvs[n][0] = findUvs->second[0];
|
|
|
|
triangleUvs[n][1] = findUvs->second[1];
|
|
|
|
triangleUvs[n][2] = findUvs->second[2];
|
|
|
|
}
|
|
|
|
m_object->setTriangleVertexUvs(triangleUvs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UvMapGenerator::generate()
|
|
|
|
{
|
|
|
|
if (nullptr == m_object)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (nullptr == m_snapshot)
|
|
|
|
return;
|
|
|
|
|
|
|
|
packUvs();
|
|
|
|
generateTextureColorImage();
|
|
|
|
generateUvCoords();
|
|
|
|
|
|
|
|
m_mesh = std::make_unique<ModelMesh>(*m_object);
|
|
|
|
m_mesh->setTextureImage(new QImage(*m_textureColorImage));
|
2022-10-25 11:31:44 +00:00
|
|
|
}
|