107 QVector<VertexAttributeDataExt> vertexAttributes;
109 vertexAttributes.resize(mesh->mNumVertices);
112 if (mesh->HasPositions()) {
113 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
114 const auto vertex = mesh->mVertices[index];
115 vertexAttributes[index].aData.position = QVector3D(vertex.x, vertex.y, vertex.z);
120 if (mesh->HasNormals()) {
121 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
122 const auto normal = mesh->mNormals[index];
123 vertexAttributes[index].aData.normal = QVector3D(normal.x, normal.y, normal.z);
128 if (mesh->HasTextureCoords(0)) {
129 const auto texCoords = mesh->mTextureCoords[0];
131 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
132 const auto uv = texCoords[index];
133 vertexAttributes[index].aData.uv0 = QVector3D(uv.x, uv.y, 0.0f);
136 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
137 const auto uv = texCoords[index];
138 vertexAttributes[index].aData.uv0 = QVector3D(uv.x, uv.y, uv.z);
144 if (mesh->HasTextureCoords(1)) {
145 const auto texCoords = mesh->mTextureCoords[1];
147 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
148 const auto uv = texCoords[index];
149 vertexAttributes[index].aData.uv1 = QVector3D(uv.x, uv.y, 0.0f);
152 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
153 const auto uv = texCoords[index];
154 vertexAttributes[index].aData.uv1 = QVector3D(uv.x, uv.y, uv.z);
160 if (mesh->HasTangentsAndBitangents()) {
161 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
162 const auto tangent = mesh->mTangents[index];
163 const auto binormal = mesh->mBitangents[index];
164 vertexAttributes[index].aData.tangent = QVector3D(tangent.x, tangent.y, tangent.z);
165 vertexAttributes[index].aData.binormal = QVector3D(binormal.x, binormal.y, binormal.z);
170 if (mesh->HasVertexColors(0)) {
171 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
172 const auto color = mesh->mColors[0][index];
173 vertexAttributes[index].aData.color = QVector4D(color.r, color.g, color.b, color.a);
178 if (mesh->HasBones()) {
179 for (uint i = 0; i < mesh->mNumBones; ++i) {
181 for (uint j = 0; j < mesh->mBones[i]->mNumWeights; ++j) {
182 quint32 vertexId = mesh->mBones[i]->mWeights[j].mVertexId;
183 float weight = mesh->mBones[i]->mWeights[j].mWeight;
190 if (vertexAttributes[vertexId].boneWeights.x() == 0.0f) {
191 vertexAttributes[vertexId].boneIndexes.x = qint32(vId);
192 vertexAttributes[vertexId].boneWeights.setX(weight);
193 }
else if (vertexAttributes[vertexId].boneWeights.y() == 0.0f) {
194 vertexAttributes[vertexId].boneIndexes.y = qint32(vId);
195 vertexAttributes[vertexId].boneWeights.setY(weight);
196 }
else if (vertexAttributes[vertexId].boneWeights.z() == 0.0f) {
197 vertexAttributes[vertexId].boneIndexes.z = qint32(vId);
198 vertexAttributes[vertexId].boneWeights.setZ(weight);
199 }
else if (vertexAttributes[vertexId].boneWeights.w() == 0.0f) {
200 vertexAttributes[vertexId].boneIndexes.w = qint32(vId);
201 vertexAttributes[vertexId].boneWeights.setW(weight);
203 qWarning(
"vertexId %d has already 4 weights and index %d's weight %f will be ignored.", vertexId, vId, weight);
210 if (requirments.numMorphTargets > 0) {
211 for (
unsigned int index = 0; index < mesh->mNumVertices; ++index) {
212 vertexAttributes[index].targetAData.resize(requirments.numMorphTargets);
214 for (uint i = 0; i < requirments.numMorphTargets; ++i) {
215 if (i >= mesh->mNumAnimMeshes)
218 auto animMesh = mesh->mAnimMeshes[i];
219 if (animMesh->HasPositions()) {
220 const auto vertex = animMesh->mVertices[index];
221 vertexAttributes[index].targetAData[i].position = QVector3D(vertex.x, vertex.y, vertex.z);
223 if (animMesh->HasNormals()) {
224 const auto normal = animMesh->mNormals[index];
225 vertexAttributes[index].targetAData[i].normal = QVector3D(normal.x, normal.y, normal.z);
227 if (animMesh->HasTangentsAndBitangents()) {
228 const auto tangent = animMesh->mTangents[index];
229 const auto binormal = animMesh->mBitangents[index];
230 vertexAttributes[index].targetAData[i].tangent = QVector3D(tangent.x, tangent.y, tangent.z);
231 vertexAttributes[index].targetAData[i].binormal = QVector3D(binormal.x, binormal.y, binormal.z);
233 if (animMesh->HasTextureCoords(0)) {
234 const auto texCoords = animMesh->mTextureCoords[0];
235 const auto uv = texCoords[index];
236 vertexAttributes[index].targetAData[i].uv0 = QVector3D(uv.x, uv.y, uv.z);
238 if (animMesh->HasTextureCoords(1)) {
239 const auto texCoords = animMesh->mTextureCoords[1];
240 const auto uv = texCoords[index];
241 vertexAttributes[index].targetAData[i].uv1 = QVector3D(uv.x, uv.y, uv.z);
243 if (animMesh->HasVertexColors(0)) {
244 const auto color = animMesh->mColors[0][index];
245 vertexAttributes[index].targetAData[i].color = QVector4D(color.r, color.g, color.b, color.a);
251 return vertexAttributes;
498 const QVector<quint32> &indexes,
499 float normalMergeAngle = 60.0f,
500 float normalSplitAngle = 25.0f)
502 QVector<QVector3D> positions;
503 positions.reserve(vertexAttributes.size());
504 QVector<QVector3D> normals;
505 normals.reserve(vertexAttributes.size());
506 for (
const auto &vertex : std::as_const(vertexAttributes)) {
507 positions.append(vertex.aData.position);
508 normals.append(vertex.aData.normal);
511 QVector<QSSGMesh::MeshVertexSplit> splitVertices;
512 auto lods = QSSGMesh::generateMeshLevelsOfDetail(positions, normals, indexes, splitVertices, normalMergeAngle, normalSplitAngle);
516 for (
const auto &split : std::as_const(splitVertices)) {
517 auto newVertex = vertexAttributes[split.sourceIndex];
518 newVertex.aData.normal = split.normal;
519 vertexAttributes.append(newVertex);
528 const MeshList &meshes,
529 bool useFloatJointIndices,
530 bool generateLevelsOfDetail,
531 float normalMergeAngle,
532 float normalSplitAngle,
533 QString &errorString)
535 Q_UNUSED(errorString);
543 for (
const auto *mesh : meshes)
544 requirments.collectRequirmentsForMesh(mesh);
548 QByteArray indexBufferData;
550 QVector<SubsetEntryData> subsetData;
556 quint32 baseIndex = 0;
560 const QSSGMesh::Mesh::ComponentType indexType = QSSGMesh::Mesh::ComponentType::UnsignedInt32;
562 for (
const auto *mesh : meshes) {
567 QVector<quint32> indexes;
568 indexes.reserve(mesh->mNumFaces * 3);
569 for (
unsigned int faceIndex = 0; faceIndex < mesh->mNumFaces; ++faceIndex) {
570 const auto face = mesh->mFaces[faceIndex];
572 Q_ASSERT(face.mNumIndices == 3);
575 indexes.append(quint32(face.mIndices[0]));
576 indexes.append(quint32(face.mIndices[1]));
577 indexes.append(quint32(face.mIndices[2]));
581 auto vertexAttributes = getVertexAttributeData(mesh, requirments);
584 quint32 baseIndexOffset = indexBufferData.size() / QSSGMesh::MeshInternal::byteSizeForComponentType(indexType);
585 QVector<quint32> lodIndexes;
586 QVector<QSSGMesh::Mesh::Lod> meshLods;
589 if (generateLevelsOfDetail) {
594 auto lods = generateMeshLevelsOfDetail(vertexAttributes, indexes, normalMergeAngle, normalSplitAngle);
595 for (
const auto &lodEntry : std::as_const(lods)) {
596 QSSGMesh::Mesh::Lod lod;
597 lod.offset = baseIndexOffset;
598 lod.count = lodEntry.indexes.size();
599 lod.distance = lodEntry.distance;
600 meshLods.push_front(lod);
601 baseIndexOffset += lod.count;
603 auto currentLodIndexes = lodEntry.indexes;
604 QSSGMesh::optimizeVertexCache(currentLodIndexes.data(), currentLodIndexes.data(), currentLodIndexes.size(), vertexAttributes.size());
605 lodIndexes += currentLodIndexes;
611 QSSGMesh::optimizeVertexCache(indexes.data(), indexes.data(), indexes.size(), vertexAttributes.size());
614 QVector<quint32> combinedIndexValues = lodIndexes + indexes;
616 for (
auto &index : combinedIndexValues)
618 indexBufferData += QByteArray(
reinterpret_cast<
const char *>(combinedIndexValues.constData()),
619 combinedIndexValues.size() * QSSGMesh::MeshInternal::byteSizeForComponentType(indexType));
626 SubsetEntryData subsetEntry;
627 subsetEntry.indexOffset = baseIndexOffset;
628 subsetEntry.indexLength = indexes.size();
629 subsetEntry.name = QString::fromUtf8(scene.mMaterials[mesh->mMaterialIndex]->GetName().C_Str());
630 subsetEntry.lightmapWidth = 0;
631 subsetEntry.lightmapHeight = 0;
632 subsetEntry.lods = meshLods;
633 subsetData.append(subsetEntry);
636 baseIndex += vertexAttributes.size();
638 vertexBufferData.targetVData.resize(requirments.numMorphTargets);
639 for (
const auto &vertex : std::as_const(vertexAttributes))
640 vertexBufferData.addVertexAttributeData(vertex, requirments);
645 QVector<QSSGMesh::AssetVertexEntry> entries = vertexBufferData.createEntries(requirments);
647 QVector<QSSGMesh::AssetMeshSubset> subsets;
648 for (
const SubsetEntryData &subset : subsetData) {
651 quint32(subset.indexLength),
652 quint32(subset.indexOffset),
654 subset.lightmapWidth,
655 subset.lightmapHeight,
677 QSSGMesh::Mesh mesh = QSSGMesh::Mesh::fromAssetData(entries,
681 requirments.numMorphTargets,
682 numTargetComponents(requirments));