6#include <assimp/Importer.hpp>
7#include <assimp/scene.h>
8#include <assimp/Logger.hpp>
9#include <assimp/DefaultLogger.hpp>
10#include <assimp/postprocess.h>
11#include <assimp/importerdesc.h>
13#include <QtQuick3DUtils/private/qssgutils_p.h>
15#include <QtCore/qstring.h>
16#include <QtCore/QHash>
41 QVector<QSSGMesh::Mesh::Lod>
lods;
69 bool needsPositionData =
false;
70 bool needsNormalData =
false;
71 bool needsTangentData =
false;
72 bool needsVertexColorData =
false;
73 unsigned uv0Components = 0;
74 unsigned uv1Components = 0;
75 bool needsUV0Data =
false;
76 bool needsUV1Data =
false;
77 bool needsBones =
false;
78 bool useFloatJointIndices =
false;
84 bool needsTargetPositionData =
false;
85 bool needsTargetNormalData =
false;
86 bool needsTargetTangentData =
false;
87 bool needsTargetVertexColorData =
false;
88 bool needsTargetUV0Data =
false;
89 bool needsTargetUV1Data =
false;
92 uv0Components =
qMax(mesh->mNumUVComponents[0], uv0Components);
93 uv1Components =
qMax(mesh->mNumUVComponents[1], uv1Components);
94 needsUV0Data |= mesh->HasTextureCoords(0);
95 needsUV1Data |= mesh->HasTextureCoords(1);
96 needsPositionData |= mesh->HasPositions();
97 needsNormalData |= mesh->HasNormals();
98 needsTangentData |= mesh->HasTangentsAndBitangents();
99 needsVertexColorData |=mesh->HasVertexColors(0);
100 needsBones |= mesh->HasBones();
101 numMorphTargets = mesh->mNumAnimMeshes;
102 if (numMorphTargets && mesh->mAnimMeshes) {
103 for (
uint i = 0;
i < numMorphTargets; ++
i) {
104 auto animMesh = mesh->mAnimMeshes[
i];
105 needsTargetPositionData |= animMesh->HasPositions();
106 needsTargetNormalData |= animMesh->HasNormals();
107 needsTargetTangentData |= animMesh->HasTangentsAndBitangents();
108 needsTargetVertexColorData |= animMesh->HasVertexColors(0);
109 needsTargetUV0Data |= animMesh->HasTextureCoords(0);
110 needsTargetUV1Data |= animMesh->HasTextureCoords(1);
118 QVector<VertexAttributeDataExt> vertexAttributes;
120 vertexAttributes.resize(mesh->mNumVertices);
123 if (mesh->HasPositions()) {
125 const auto vertex = mesh->mVertices[
index];
126 vertexAttributes[
index].aData.position =
QVector3D(vertex.x, vertex.y, vertex.z);
131 if (mesh->HasNormals()) {
133 const auto normal = mesh->mNormals[
index];
134 vertexAttributes[
index].aData.normal =
QVector3D(normal.x, normal.y, normal.z);
139 if (mesh->HasTextureCoords(0)) {
140 const auto texCoords = mesh->mTextureCoords[0];
141 if (requirments.uv0Components == 2) {
143 const auto uv = texCoords[
index];
146 }
else if (requirments.uv0Components == 3) {
148 const auto uv = texCoords[
index];
155 if (mesh->HasTextureCoords(1)) {
156 const auto texCoords = mesh->mTextureCoords[1];
157 if (requirments.uv1Components == 2) {
159 const auto uv = texCoords[
index];
162 }
else if (requirments.uv1Components == 3) {
164 const auto uv = texCoords[
index];
171 if (mesh->HasTangentsAndBitangents()) {
173 const auto tangent = mesh->mTangents[
index];
174 const auto binormal = mesh->mBitangents[
index];
175 vertexAttributes[
index].aData.tangent =
QVector3D(tangent.x, tangent.y, tangent.z);
176 vertexAttributes[
index].aData.binormal =
QVector3D(binormal.x, binormal.y, binormal.z);
181 if (mesh->HasVertexColors(0)) {
189 if (mesh->HasBones()) {
190 for (
uint i = 0;
i < mesh->mNumBones; ++
i) {
192 for (
uint j = 0;
j < mesh->mBones[
i]->mNumWeights; ++
j) {
193 quint32 vertexId = mesh->mBones[
i]->mWeights[
j].mVertexId;
194 float weight = mesh->mBones[
i]->mWeights[
j].mWeight;
201 if (vertexAttributes[vertexId].boneWeights.x() == 0.0f) {
202 vertexAttributes[vertexId].boneIndexes.x =
qint32(vId);
203 vertexAttributes[vertexId].boneWeights.setX(
weight);
204 }
else if (vertexAttributes[vertexId].boneWeights.y() == 0.0f) {
205 vertexAttributes[vertexId].boneIndexes.y =
qint32(vId);
206 vertexAttributes[vertexId].boneWeights.setY(
weight);
207 }
else if (vertexAttributes[vertexId].boneWeights.z() == 0.0f) {
208 vertexAttributes[vertexId].boneIndexes.z =
qint32(vId);
209 vertexAttributes[vertexId].boneWeights.setZ(
weight);
210 }
else if (vertexAttributes[vertexId].boneWeights.w() == 0.0f) {
211 vertexAttributes[vertexId].boneIndexes.w =
qint32(vId);
212 vertexAttributes[vertexId].boneWeights.setW(
weight);
214 qWarning(
"vertexId %d has already 4 weights and index %d's weight %f will be ignored.", vertexId, vId,
weight);
221 if (requirments.numMorphTargets > 0) {
223 vertexAttributes[
index].targetAData.resize(requirments.numMorphTargets);
225 for (
uint i = 0;
i < requirments.numMorphTargets; ++
i) {
226 if (
i >= mesh->mNumAnimMeshes)
229 auto animMesh = mesh->mAnimMeshes[
i];
230 if (animMesh->HasPositions()) {
231 const auto vertex = animMesh->mVertices[
index];
232 vertexAttributes[
index].targetAData[
i].position =
QVector3D(vertex.x, vertex.y, vertex.z);
234 if (animMesh->HasNormals()) {
235 const auto normal = animMesh->mNormals[
index];
236 vertexAttributes[
index].targetAData[
i].normal =
QVector3D(normal.x, normal.y, normal.z);
238 if (animMesh->HasTangentsAndBitangents()) {
239 const auto tangent = animMesh->mTangents[
index];
240 const auto binormal = animMesh->mBitangents[
index];
241 vertexAttributes[
index].targetAData[
i].tangent =
QVector3D(tangent.x, tangent.y, tangent.z);
242 vertexAttributes[
index].targetAData[
i].binormal =
QVector3D(binormal.x, binormal.y, binormal.z);
244 if (animMesh->HasTextureCoords(0)) {
245 const auto texCoords = animMesh->mTextureCoords[0];
246 const auto uv = texCoords[
index];
247 vertexAttributes[
index].targetAData[
i].uv0 =
QVector3D(uv.x, uv.y, uv.z);
249 if (animMesh->HasTextureCoords(1)) {
250 const auto texCoords = animMesh->mTextureCoords[1];
251 const auto uv = texCoords[
index];
252 vertexAttributes[
index].targetAData[
i].uv1 =
QVector3D(uv.x, uv.y, uv.z);
254 if (animMesh->HasVertexColors(0)) {
255 const auto color = animMesh->mColors[0][
index];
262 return vertexAttributes;
284 if (requirments.needsPositionData)
287 if (requirments.needsNormalData)
291 if (requirments.needsUV0Data) {
292 if (requirments.uv0Components == 2) {
301 if (requirments.needsUV1Data) {
302 if (requirments.uv1Components == 2) {
312 if (requirments.needsTangentData) {
318 if (requirments.needsVertexColorData)
323 if (requirments.needsBones) {
324 if (requirments.useFloatJointIndices) {
334 for (
uint i = 0;
i < requirments.numMorphTargets; ++
i) {
335 if (requirments.needsTargetPositionData) {
337 targetVData[
i].positionData.append(
sizeof(
float),
'\0');
339 if (requirments.needsTargetNormalData) {
341 targetVData[
i].normalData.append(
sizeof(
float),
'\0');
343 if (requirments.needsTargetTangentData) {
345 targetVData[
i].tangentData.append(
sizeof(
float),
'\0');
347 targetVData[
i].binormalData.append(
sizeof(
float),
'\0');
349 if (requirments.needsTargetUV0Data) {
351 targetVData[
i].uv0Data.append(
sizeof(
float),
'\0');
353 if (requirments.needsTargetUV1Data) {
355 targetVData[
i].uv1Data.append(
sizeof(
float),
'\0');
357 if (requirments.needsTargetVertexColorData) {
364 QVector<QSSGMesh::AssetVertexEntry> entries;
369 QSSGMesh::Mesh::ComponentType::Float32,
377 QSSGMesh::Mesh::ComponentType::Float32,
385 QSSGMesh::Mesh::ComponentType::Float32,
386 requirments.uv0Components
393 QSSGMesh::Mesh::ComponentType::Float32,
394 requirments.uv1Components
402 QSSGMesh::Mesh::ComponentType::Float32,
411 QSSGMesh::Mesh::ComponentType::Float32,
420 QSSGMesh::Mesh::ComponentType::Float32,
425 if (boneIndexData.
size() > 0) {
429 requirments.useFloatJointIndices ? QSSGMesh::Mesh::ComponentType::Float32 : QSSGMesh::Mesh::ComponentType::Int32,
435 QSSGMesh::Mesh::ComponentType::Float32,
439 for (
int i = 0;
i < int(requirments.numMorphTargets); ++
i) {
440 if (targetVData[
i].positionData.size() > 0) {
443 targetVData[
i].positionData,
444 QSSGMesh::Mesh::ComponentType::Float32,
449 if (targetVData[
i].normalData.size() > 0) {
452 targetVData[
i].normalData,
453 QSSGMesh::Mesh::ComponentType::Float32,
458 if (targetVData[
i].tangentData.size() > 0) {
461 targetVData[
i].tangentData,
462 QSSGMesh::Mesh::ComponentType::Float32,
467 if (targetVData[
i].binormalData.size() > 0) {
470 targetVData[
i].binormalData,
471 QSSGMesh::Mesh::ComponentType::Float32,
476 if (targetVData[
i].uv0Data.size() > 0) {
479 targetVData[
i].uv0Data,
480 QSSGMesh::Mesh::ComponentType::Float32,
485 if (targetVData[
i].uv1Data.size() > 0) {
488 targetVData[
i].uv1Data,
489 QSSGMesh::Mesh::ComponentType::Float32,
494 if (targetVData[
i].vertexColorData.size() > 0) {
497 targetVData[
i].vertexColorData,
498 QSSGMesh::Mesh::ComponentType::Float32,
508QVector<QPair<float, QVector<quint32>>>
generateMeshLevelsOfDetail(QVector<VertexAttributeDataExt> &vertexAttributes, QVector<quint32> &indexes,
float normalMergeAngle = 60.0f,
float normalSplitAngle = 25.0f)
516 positions.reserve(vertexAttributes.size());
517 QVector<QVector3D> normals;
518 normals.reserve(vertexAttributes.size());
519 for (
const auto &vertex : vertexAttributes) {
521 normals.append(vertex.aData.normal);
524 QVector<QVector3D> splitVertexNormals;
525 QVector<quint32> splitVertexIndices;
526 quint32 splitVertexCount = vertexAttributes.size();
528 const float targetError = std::numeric_limits<float>::max();
531 const quint32 indexCount = indexes.size();
534 QVector<QPair<float, QVector<quint32>>> lods;
536 while (indexTarget < indexCount) {
538 QVector<quint32> newIndexes;
539 newIndexes.resize(indexCount);
543 if (newLength < lastIndexCount * 1.5f) {
544 indexTarget = indexTarget * 1.5f;
549 if (newLength == 0 || (newLength >= (indexCount * 0.75f)))
552 newIndexes.resize(newLength);
555 if (recalculateNormals) {
557 QVector<QVector3D> faceNormals;
559 QVector<quint32> culledIndexes;
560 for (
quint32 j = 0;
j < newIndexes.size();
j += 3) {
572 if (faceArea != 0.0f) {
573 faceNormals.append(faceNormal);
574 faceNormals.append(faceNormal);
575 faceNormals.append(faceNormal);
576 culledIndexes.append({newIndexes[
j], newIndexes[
j + 1], newIndexes[
j + 2]});
580 if (newIndexes.size() != culledIndexes.size())
581 newIndexes = culledIndexes;
586 QHash<QVector3D, QVector<quint32>> positionHash;
587 for (
quint32 i = 0;
i < newIndexes.size(); ++
i) {
597 QVector<QPair<quint32, quint32>> remapIndexes;
598 for (
quint32 positionIndex = 0; positionIndex < newIndexes.size(); ++positionIndex) {
601 const QVector3D &faceNormal = faceNormals[positionIndex];
604 const auto &sharedPositions = positionHash.value(
position);
605 for (
auto positionIndex2 : sharedPositions) {
606 if (positionIndex == positionIndex2) {
608 newNormal += faceNormal;
610 const QVector3D &faceNormal2 = faceNormals[positionIndex2];
612 newNormal += faceNormal2;
630 if (theta < normalSplitThreshold) {
631 splitVertexIndices.append(
index);
632 splitVertexNormals.append(newNormal.normalized());
633 remapIndexes.append({positionIndex, splitVertexCount++});
638 for (
auto pair : remapIndexes)
639 newIndexes[pair.first] = pair.second;
642 lods.append({
error * scaleFactor, newIndexes});
643 indexTarget =
qMax(newLength, indexTarget) * 2;
644 lastIndexCount = newLength;
651 for (
quint32 i = 0;
i < splitVertexIndices.size(); ++
i) {
654 auto newVertex = vertexAttributes[
index];
655 newVertex.aData.
normal = newNormal;
656 vertexAttributes.append(newVertex);
666 bool useFloatJointIndices,
667 bool generateLevelsOfDetail,
668 float normalMergeAngle,
669 float normalSplitAngle,
678 VertexDataRequirments requirments;
679 requirments.useFloatJointIndices = useFloatJointIndices;
680 for (
const auto *mesh : meshes)
681 requirments.collectRequirmentsForMesh(mesh);
686 VertexBufferDataExt vertexBufferData;
687 QVector<SubsetEntryData> subsetData;
699 for (
const auto *mesh : meshes) {
704 QVector<quint32> indexes;
705 indexes.reserve(mesh->mNumFaces * 3);
718 auto vertexAttributes = getVertexAttributeData(mesh, requirments);
722 QVector<quint32> lodIndexes;
723 QVector<QSSGMesh::Mesh::Lod> meshLods;
726 if (generateLevelsOfDetail) {
731 auto lods = generateMeshLevelsOfDetail(vertexAttributes, indexes, normalMergeAngle, normalSplitAngle);
732 for (
const auto &lodPair : lods) {
735 lod.count = lodPair.second.size();
736 lod.distance = lodPair.first;
737 meshLods.push_front(
lod);
738 baseIndexOffset +=
lod.count;
740 auto currentLodIndexes = lodPair.second;
742 lodIndexes += currentLodIndexes;
751 QVector<quint32> combinedIndexValues = lodIndexes + indexes;
753 for (
auto &
index : combinedIndexValues)
755 indexBufferData +=
QByteArray(
reinterpret_cast<const char *
>(combinedIndexValues.constData()),
763 SubsetEntryData subsetEntry;
764 subsetEntry.indexOffset = baseIndexOffset;
765 subsetEntry.indexLength = indexes.size();
767 subsetEntry.lightmapWidth = 0;
768 subsetEntry.lightmapHeight = 0;
769 subsetEntry.lods = meshLods;
770 subsetData.append(subsetEntry);
773 baseIndex += vertexAttributes.size();
775 vertexBufferData.targetVData.resize(requirments.numMorphTargets);
776 for (
const auto &vertex : vertexAttributes)
777 vertexBufferData.addVertexAttributeData(vertex, requirments);
782 QVector<QSSGMesh::AssetVertexEntry> entries = vertexBufferData.createEntries(requirments);
784 QVector<QSSGMesh::AssetMeshSubset> subsets;
785 for (
const SubsetEntryData &subset : subsetData) {
791 subset.lightmapWidth,
792 subset.lightmapHeight,
797 auto numTargetComponents = [](VertexDataRequirments req) {
799 if (req.needsTargetPositionData)
801 if (req.needsTargetNormalData)
803 if (req.needsTargetTangentData)
805 if (req.needsTargetVertexColorData)
807 if (req.needsTargetUV0Data)
809 if (req.needsTargetUV1Data)
815 subsets, requirments.numMorphTargets,
816 numTargetComponents(requirments));
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
static Mesh fromAssetData(const QVector< AssetVertexEntry > &vbufEntries, const QByteArray &indexBufferData, ComponentType indexComponentType, const QVector< AssetMeshSubset > &subsets, quint32 numTargets=0, quint32 numTargetComps=0)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
The QVector2D class represents a vector or vertex in 2D space.
The QVector3D class represents a vector or vertex in 3D space.
static QVector3D normal(QVector3D v1, QVector3D v2) noexcept
Returns the unit normal vector of a plane spanned by vectors v1 and v2, which must not be parallel to...
constexpr float y() const noexcept
Returns the y coordinate of this point.
constexpr float x() const noexcept
Returns the x coordinate of this point.
static constexpr float dotProduct(QVector3D v1, QVector3D v2) noexcept
Returns the dot product of v1 and v2.
static constexpr QVector3D crossProduct(QVector3D v1, QVector3D v2) noexcept
Returns the cross-product of vectors v1 and v2, which is normal to the plane spanned by v1 and v2.
The QVector4D class represents a vector or vertex in 4D space.
QSSGMesh::Mesh generateMeshData(const aiScene &scene, const MeshList &meshes, bool useFloatJointIndices, bool generateLevelsOfDetail, float normalMergeAngle, float normalSplitAngle, QString &errorString)
float simplifyScale(const float *vertexPositions, size_t vertexCount, size_t vertexPositionsStride)
void optimizeVertexCache(unsigned int *destination, const unsigned int *indices, size_t indexCount, size_t vertexCount)
size_t simplifyMesh(unsigned int *destination, const unsigned int *indices, size_t indexCount, const float *vertexPositions, size_t vertexCount, size_t vertexPositionsStride, size_t targetIndexCount, float targetError, unsigned int options, float *resultError)
float Q_QUICK3DUTILS_EXPORT normalize(QVector3D &v)
Combined button and popup list for selecting options.
QVector< QPair< float, QVector< quint32 > > > generateMeshLevelsOfDetail(QVector< VertexAttributeDataExt > &vertexAttributes, QVector< quint32 > &indexes, float normalMergeAngle=60.0f, float normalSplitAngle=25.0f)
QVector< VertexAttributeDataExt > getVertexAttributeData(const aiMesh *mesh, const VertexDataRequirments &requirments)
static const QCssKnownValue positions[NumKnownPositionModes - 1]
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
bool qFuzzyIsNull(qfloat16 f) noexcept
constexpr float qDegreesToRadians(float degrees)
constexpr const T & qMax(const T &a, const T &b)
GLint GLfloat GLfloat GLfloat v2
GLenum GLsizeiptr const void GLsizei faceIndex
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLuint GLuint GLfloat weight
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static quint32 byteSizeForComponentType(Mesh::ComponentType componentType)
static const char * getNormalAttrName()
static const char * getUV1AttrName()
static const char * getTexBinormalAttrName()
static const char * getPositionAttrName()
static const char * getTexTanAttrName()
static const char * getColorAttrName()
static const char * getJointAttrName()
static const char * getUV0AttrName()
static const char * getWeightAttrName()
QVector< QSSGMesh::Mesh::Lod > lods
QVector< VertexAttributeData > targetAData
VertexAttributeData aData
void addVertexAttributeData(const VertexAttributeDataExt &vertex, const VertexDataRequirments &requirments)
QVector< QSSGMesh::AssetVertexEntry > createEntries(const VertexDataRequirments &requirments)
QVector< VertexBufferData > targetVData
QByteArray boneWeightData
QByteArray vertexColorData
void collectRequirmentsForMesh(const aiMesh *mesh)