1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qssglightmapuvgenerator_p.h"
5#include "xatlas.h"
6
7QT_BEGIN_NAMESPACE
8
9QSSGLightmapUVGeneratorResult QSSGLightmapUVGenerator::run(const QByteArray &positions,
10 const QByteArray &normals,
11 const QByteArray &uv0,
12 const QByteArray &index,
13 QSSGMesh::Mesh::ComponentType indexComponentType,
14 uint baseResolution)
15{
16 QSSGLightmapUVGeneratorResult result;
17
18 xatlas::MeshDecl meshInfo;
19
20 if (indexComponentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16) {
21 meshInfo.indexFormat = xatlas::IndexFormat::UInt16;
22 } else if (indexComponentType == QSSGMesh::Mesh::ComponentType::UnsignedInt32) {
23 meshInfo.indexFormat = xatlas::IndexFormat::UInt32;
24 } else {
25 qWarning(msg: "Lightmap UV generator: Unknown index type %d; cannot generate",
26 int(indexComponentType));
27 return result;
28 }
29
30 const quint32 indexComponentByteSize = QSSGMesh::MeshInternal::byteSizeForComponentType(componentType: indexComponentType);
31 const quint32 indexCount = index.size() / indexComponentByteSize;
32
33 meshInfo.indexCount = indexCount;
34 meshInfo.indexData = index.constData();
35
36 const quint32 positionStride = 3 * sizeof(float);
37 const quint32 normalStride = 3 * sizeof(float);
38 const quint32 uvStride = 2 * sizeof(float);
39
40 meshInfo.vertexCount = positions.size() / positionStride;
41 meshInfo.vertexPositionData = positions.data();
42 meshInfo.vertexPositionStride = positionStride;
43
44 if (!normals.isEmpty()) {
45 meshInfo.vertexNormalData = normals.constData();
46 meshInfo.vertexNormalStride = normalStride;
47 } else {
48 meshInfo.vertexNormalData = nullptr;
49 meshInfo.vertexNormalStride = 0;
50 }
51
52 if (!uv0.isEmpty()) {
53 meshInfo.vertexUvData = uv0.constData();
54 meshInfo.vertexUvStride = uvStride;
55 } else {
56 meshInfo.vertexUvData = nullptr;
57 meshInfo.vertexUvStride = 0;
58 }
59
60 xatlas::PackOptions packOptions;
61 packOptions.maxChartSize = 4096;
62 packOptions.padding = 1;
63 packOptions.resolution = baseResolution;
64 packOptions.blockAlign = true;
65
66 xatlas::ChartOptions chartOptions;
67
68 xatlas::Atlas *atlas = xatlas::Create();
69 xatlas::AddMeshError err = xatlas::AddMesh(atlas, meshDecl: meshInfo, meshCountHint: 1);
70 if (err != xatlas::AddMeshError::Success) {
71 qWarning(msg: "Failed to register mesh for UV unwrapping (error %d)", int(err));
72 xatlas::Destroy(atlas);
73 return result;
74 }
75 xatlas::Generate(atlas, chartOptions, packOptions);
76
77 const uint32_t textureWidth = atlas->width;
78 const uint32_t textureHeight = atlas->height;
79 if (textureWidth == 0 || textureHeight == 0) {
80 qWarning(msg: "Texture size is empty, UV unwrapping failed");
81 xatlas::Destroy(atlas);
82 return result;
83 }
84 result.lightmapWidth = textureWidth;
85 result.lightmapHeight = textureHeight;
86
87 const xatlas::Mesh &output = atlas->meshes[0];
88 result.lightmapUVChannel.resize(size: output.vertexCount * uvStride);
89 result.vertexMap.resize(size: output.vertexCount);
90
91 float *uvPtr = reinterpret_cast<float *>(result.lightmapUVChannel.data());
92 for (uint32_t i = 0; i < output.vertexCount; ++i) {
93 const float u = output.vertexArray[i].uv[0] / float(textureWidth);
94 const float v = output.vertexArray[i].uv[1] / float(textureHeight);
95 *uvPtr++ = u;
96 *uvPtr++ = v;
97 result.vertexMap[i] = output.vertexArray[i].xref;
98 }
99
100 result.indexData.resize(size: output.indexCount * sizeof(quint32));
101 quint32 *indexPtr = reinterpret_cast<quint32 *>(result.indexData.data());
102 for (uint32_t i = 0; i < output.indexCount; ++i)
103 *indexPtr++ = output.indexArray[i];
104
105 xatlas::Destroy(atlas);
106
107 return result;
108}
109
110QT_END_NAMESPACE
111

source code of qtquick3d/src/utils/qssglightmapuvgenerator.cpp