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>
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);
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];
143 const auto uv = texCoords[
index];
148 const auto uv = texCoords[
index];
155 if (mesh->HasTextureCoords(1)) {
156 const auto texCoords = mesh->mTextureCoords[1];
159 const auto uv = texCoords[
index];
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);
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;
337 targetVData[
i].positionData.
append(
sizeof(
float),
'\0');
341 targetVData[
i].normalData.
append(
sizeof(
float),
'\0');
345 targetVData[
i].tangentData.
append(
sizeof(
float),
'\0');
347 targetVData[
i].binormalData.
append(
sizeof(
float),
'\0');
351 targetVData[
i].uv0Data.
append(
sizeof(
float),
'\0');
355 targetVData[
i].uv1Data.
append(
sizeof(
float),
'\0');
369 QSSGMesh::Mesh::ComponentType::Float32,
377 QSSGMesh::Mesh::ComponentType::Float32,
385 QSSGMesh::Mesh::ComponentType::Float32,
393 QSSGMesh::Mesh::ComponentType::Float32,
402 QSSGMesh::Mesh::ComponentType::Float32,
411 QSSGMesh::Mesh::ComponentType::Float32,
420 QSSGMesh::Mesh::ComponentType::Float32,
425 if (boneIndexData.
size() > 0) {
429 QSSGMesh::Mesh::ComponentType::Int32,
435 QSSGMesh::Mesh::ComponentType::Float32,
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,
519 for (
const auto &vertex : vertexAttributes) {
521 normals.
append(vertex.aData.normal);
526 quint32 splitVertexCount = vertexAttributes.
size();
528 const float targetError = std::numeric_limits<float>::max();
529 const float *vertexData =
reinterpret_cast<const float *
>(
positions.constData());
536 while (indexTarget < indexCount) {
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) {
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;
598 for (
quint32 positionIndex = 0; positionIndex < newIndexes.
size(); ++positionIndex) {
601 const QVector3D &faceNormal = faceNormals[positionIndex];
605 for (
auto positionIndex2 : sharedPositions) {
606 if (positionIndex == positionIndex2) {
608 newNormal += faceNormal;
610 const QVector3D &faceNormal2 = faceNormals[positionIndex2];
612 newNormal += faceNormal2;
628 const QVector3D &originalNormal = vertexAttributes[
index].aData.normal;
630 if (theta < normalSplitThreshold) {
633 remapIndexes.
append({positionIndex, splitVertexCount++});
638 for (
auto pair : remapIndexes)
639 newIndexes[pair.first] = pair.second;
643 indexTarget =
qMax(newLength, indexTarget) * 2;
644 lastIndexCount = newLength;
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;
699 for (
const auto *mesh : meshes) {
705 indexes.
reserve(mesh->mNumFaces * 3);
718 auto vertexAttributes = getVertexAttributeData(mesh, requirments);
726 if (generateLevelsOfDetail) {
731 auto lods = generateMeshLevelsOfDetail(vertexAttributes, indexes, normalMergeAngle, normalSplitAngle);
732 for (
const auto &lodPair : lods) {
734 lod.offset = baseIndexOffset;
735 lod.count = lodPair.second.size();
736 lod.distance = lodPair.first;
738 baseIndexOffset +=
lod.count;
740 auto currentLodIndexes = lodPair.second;
742 lodIndexes += currentLodIndexes;
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);
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.
T value(const Key &key) const noexcept
qsizetype size() const noexcept
const_pointer constData() const noexcept
void push_front(rvalue_ref t)
void reserve(qsizetype size)
void resize(qsizetype size)
void append(parameter_type t)
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.
QVector3D normalized() const noexcept
Returns the normalized unit vector form of this vector.
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)
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)
float Q_QUICK3DUTILS_EXPORT normalize(QVector3D &v)
static const QCssKnownValue positions[NumKnownPositionModes - 1]
DBusConnection const char DBusError * error
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
bool needsVertexColorData
void collectRequirmentsForMesh(const aiMesh *mesh)
bool needsTargetNormalData
bool useFloatJointIndices
bool needsTargetPositionData
bool needsTargetTangentData
bool needsTargetVertexColorData