8#include <QtCore/qurl.h>
9#include <QtCore/qbytearrayalgorithms.h>
10#include <QtGui/QQuaternion>
11#include <QtQml/QQmlFile>
13#include <QtQuick3DAssetImport/private/qssgassetimporterfactory_p.h>
14#include <QtQuick3DAssetImport/private/qssgassetimporter_p.h>
15#include <QtQuick3DAssetUtils/private/qssgscenedesc_p.h>
16#include <QtQuick3DAssetUtils/private/qssgsceneedit_p.h>
19#include <assimp/Importer.hpp>
20#include <assimp/scene.h>
21#include <assimp/Logger.hpp>
22#include <assimp/DefaultLogger.hpp>
23#include <assimp/postprocess.h>
24#include <assimp/material.h>
25#include <assimp/GltfMaterial.h>
26#include <assimp/importerdesc.h>
27#include <assimp/IOSystem.hpp>
28#include <assimp/IOStream.hpp>
36#define AI_GLTF_FILTER_NEAREST 0x2600
37#define AI_GLTF_FILTER_LINEAR 0x2601
38#define AI_GLTF_FILTER_NEAREST_MIPMAP_NEAREST 0x2700
39#define AI_GLTF_FILTER_LINEAR_MIPMAP_NEAREST 0x2701
40#define AI_GLTF_FILTER_NEAREST_MIPMAP_LINEAR 0x2702
41#define AI_GLTF_FILTER_LINEAR_MIPMAP_LINEAR 0x2703
68using NodeMap = QHash<const aiNode *, NodeInfo>;
72[[nodiscard]]
static inline bool isEqual(
const aiUVTransform &
a,
const aiUVTransform &
b)
74 return (
a.mTranslation ==
b.mTranslation &&
a.mScaling ==
b.mScaling &&
a.mRotation ==
b.mRotation);
80 aiTextureMapping
mapping = aiTextureMapping::aiTextureMapping_UV;
89 return (
a.mapping ==
b.mapping)
90 && (std::memcmp(
a.modes,
b.modes,
sizeof(
a.modes)) == 0)
91 && (
a.minFilter ==
b.minFilter)
92 && (
a.magFilter ==
b.magFilter)
93 && (
a.uvIndex ==
b.uvIndex)
106 static_assert(std::is_same_v<
decltype(
key.info.transform), aiUVTransform>,
"Unexpected type");
118 return (
a.name ==
b.name) && (
a.info ==
b.info);
141 using MaterialMap = QVarLengthArray<QPair<const aiMaterial *, QSSGSceneDesc::Material *>>;
142 using MeshMap = QVarLengthArray<QPair<const aiMesh *, QSSGSceneDesc::Mesh *>>;
171 size_t Read(
void *pvBuffer,
size_t pSize,
size_t pCount)
override;
172 size_t Write(
const void *pvBuffer,
size_t pSize,
size_t pCount)
override;
173 aiReturn
Seek(
size_t pOffset, aiOrigin pOrigin)
override;
174 size_t Tell()
const override;
176 void Flush()
override;
186 if (
mode.startsWith(
"r"))
188 else if (
mode.startsWith(
"w"))
190 if (
mode.endsWith(
"t"))
198 auto buffer =
static_cast<char *
>(pvBuffer);
224 file.
seek(file.
pos() + pOffset);
230 return aiReturn_FAILURE;
232 return aiReturn_SUCCESS;
254 bool Exists(
const char *pFile)
const override;
256 Assimp::IOStream *
Open(
const char *pFile,
const char *pMode)
override;
257 void Close(Assimp::IOStream *pFile)
override;
285 aiMatrix4x4 *transformCorrection)
292 aiMatrix4x4 transformMatrix;
293 if (transformCorrection)
294 transformMatrix =
source.mTransformation * *transformCorrection;
296 transformMatrix =
source.mTransformation;
300 aiQuaternion rotation;
301 aiVector3D translation;
302 transformMatrix.Decompose(scaling, rotation, translation);
305 if (!sceneInfo.opt.designStudioWorkarounds) {
315 const QQuaternion rot(rotation.w, rotation.x, rotation.y, rotation.z);
329 const bool forceMipMapGeneration = sceneInfo.opt.forceMipMapGeneration;
331 if (texInfo.uvIndex > 0) {
339 if (texInfo.mapping == aiTextureMapping_UV) {
349 static const auto asQtTilingMode = [](aiTextureMapMode
mode) {
351 case aiTextureMapMode_Wrap:
353 case aiTextureMapMode_Clamp:
355 case aiTextureMapMode_Mirror:
370 const bool applyUvTransform = !
isEqual(texInfo.transform, aiUVTransform());
371 if (applyUvTransform) {
378 const auto &
transform = texInfo.transform;
383 if (sceneInfo.opt.gltfMode) {
384 const float rcos = std::cos(rotation);
385 const float rsin = std::sin(rotation);
386 posU -= 0.5f *
transform.mScaling.x * (-rcos + rsin + 1.0f);
387 posV -= (0.5f *
transform.mScaling.y * (rcos + rsin - 1.0f) + 1.0f -
transform.mScaling.y);
407 bool generateMipMaps = forceMipMapGeneration;
437 if (generateMipMaps) {
445 if (
target.name.isNull()) {
446 aiString materialName =
source.GetName();
450 const auto createTextureNode = [&sceneInfo, &
target](
const aiMaterial &material, aiTextureType textureType,
unsigned int index) {
451 const auto &srcScene = sceneInfo.scene;
453 aiString texturePath;
456 if (material.GetTexture(textureType,
index, &texturePath, &texInfo.mapping, &texInfo.uvIndex,
nullptr,
nullptr, texInfo.modes) == aiReturn_SUCCESS) {
457 if (texturePath.length > 0) {
459 if (material.Get(AI_MATKEY_UVTRANSFORM(textureType,
index),
transform) == aiReturn_SUCCESS)
462 material.Get(AI_MATKEY_UVWSRC(textureType,
index), texInfo.uvIndex);
463 material.Get(AI_MATKEY_GLTF_MAPPINGFILTER_MIN(textureType,
index), texInfo.minFilter);
464 material.Get(AI_MATKEY_GLTF_MAPPINGFILTER_MAG(textureType,
index), texInfo.magFilter);
466 auto &textureMap = sceneInfo.textureMap;
471 if (
it != textureMap.
cend()) {
482 auto aEmbeddedTex = srcScene.GetEmbeddedTextureAndIndex(texturePath.C_Str());
483 const auto &embeddedTexId = aEmbeddedTex.second;
484 if (embeddedTexId > -1) {
486 auto &embeddedTextures = sceneInfo.embeddedTextureMap;
487 textureData = embeddedTextures[embeddedTexId];
499 const quint8 flags = isCompressed ?
quint8(QSSGSceneDesc::TextureData::Flags::Compressed) : 0;
502 embeddedTextures[embeddedTexId] = textureData;
511 relativePath.replace(
"\\",
"/");
512 const auto path = sceneInfo.workingDir.absoluteFilePath(relativePath);
524 if (
type == QSSGSceneDesc::Material::RuntimeType::PrincipledMaterial) {
526 aiColor4D baseColorFactor;
527 result =
source.Get(AI_MATKEY_BASE_COLOR, baseColorFactor);
528 if (
result == aiReturn_SUCCESS) {
533 aiColor3D diffuseColor;
534 result =
source.Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor);
535 if (
result == aiReturn_SUCCESS)
540 if (
auto baseColorTexture = createTextureNode(
source, AI_MATKEY_BASE_COLOR_TEXTURE)) {
543 }
else if (
auto diffuseMapTexture = createTextureNode(
source, aiTextureType_DIFFUSE, 0)) {
548 if (
auto metalicRoughnessTexture = createTextureNode(
source, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE)) {
556 ai_real metallicFactor;
557 result =
source.Get(AI_MATKEY_METALLIC_FACTOR, metallicFactor);
558 if (
result == aiReturn_SUCCESS)
563 ai_real roughnessFactor;
564 result =
source.Get(AI_MATKEY_ROUGHNESS_FACTOR, roughnessFactor);
565 if (
result == aiReturn_SUCCESS)
569 if (
auto normalTexture = createTextureNode(
source, aiTextureType_NORMALS, 0)) {
573 result =
source.Get(AI_MATKEY_GLTF_TEXTURE_SCALE(aiTextureType_NORMALS, 0), normalScale);
574 if (
result == aiReturn_SUCCESS)
580 if (
auto occlusionTexture = createTextureNode(
source, aiTextureType_LIGHTMAP, 0)) {
584 ai_real occlusionAmount;
585 result =
source.Get(AI_MATKEY_GLTF_TEXTURE_STRENGTH(aiTextureType_LIGHTMAP, 0), occlusionAmount);
586 if (
result == aiReturn_SUCCESS)
591 if (
auto emissiveTexture = createTextureNode(
source, aiTextureType_EMISSIVE, 0))
595 aiColor3D emissiveColorFactor;
596 result =
source.Get(AI_MATKEY_COLOR_EMISSIVE, emissiveColorFactor);
597 if (
result == aiReturn_SUCCESS)
604 if (
result == aiReturn_SUCCESS && isDoubleSided)
610 result =
source.Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode);
611 if (
result == aiReturn_SUCCESS) {
631 result =
source.Get(AI_MATKEY_GLTF_ALPHACUTOFF, alphaCutoff);
632 if (
result == aiReturn_SUCCESS)
637 int shadingModel = 0;
638 result =
source.Get(AI_MATKEY_SHADING_MODEL, shadingModel);
639 if (
result == aiReturn_SUCCESS && shadingModel == aiShadingMode_Unlit)
648 ai_real clearcoatFactor = 0.0f;
649 result =
source.Get(AI_MATKEY_CLEARCOAT_FACTOR, clearcoatFactor);
650 if (
result == aiReturn_SUCCESS)
653 &QQuick3DPrincipledMaterial::setClearcoatAmount,
654 float(clearcoatFactor));
659 ai_real clearcoatRoughnessFactor = 0.0f;
660 result =
source.Get(AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR, clearcoatRoughnessFactor);
661 if (
result == aiReturn_SUCCESS)
663 "clearcoatRoughnessAmount",
664 &QQuick3DPrincipledMaterial::setClearcoatRoughnessAmount,
665 float(clearcoatRoughnessFactor));
669 if (
auto clearcoatTexture = createTextureNode(
source, AI_MATKEY_CLEARCOAT_TEXTURE))
673 if (
auto clearcoatRoughnessTexture = createTextureNode(
source, AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE))
675 "clearcoatRoughnessMap",
676 &QQuick3DPrincipledMaterial::setClearcoatRoughnessMap,
677 clearcoatRoughnessTexture);
680 if (
auto clearcoatNormalTexture = createTextureNode(
source, AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE))
688 ai_real transmissionFactor = 0.0f;
689 result =
source.Get(AI_MATKEY_TRANSMISSION_FACTOR, transmissionFactor);
690 if (
result == aiReturn_SUCCESS)
692 "transmissionFactor",
693 &QQuick3DPrincipledMaterial::setTransmissionFactor,
694 float(transmissionFactor));
699 if (
auto transmissionImage = createTextureNode(
source, AI_MATKEY_TRANSMISSION_TEXTURE))
702 &QQuick3DPrincipledMaterial::setTransmissionMap,
712 ai_real thicknessFactor = 0.0f;
713 result =
source.Get(AI_MATKEY_VOLUME_THICKNESS_FACTOR, thicknessFactor);
714 if (
result == aiReturn_SUCCESS)
720 if (
auto thicknessImage = createTextureNode(
source, AI_MATKEY_VOLUME_THICKNESS_TEXTURE))
726 ai_real attenuationDistance = 0.0f;
727 result =
source.Get(AI_MATKEY_VOLUME_ATTENUATION_DISTANCE, attenuationDistance);
728 if (
result == aiReturn_SUCCESS)
730 "attenuationDistance",
731 &QQuick3DPrincipledMaterial::setAttenuationDistance,
732 float(attenuationDistance));
737 aiColor3D attenuationColor;
738 result =
source.Get(AI_MATKEY_VOLUME_ATTENUATION_COLOR, attenuationColor);
739 if (
result == aiReturn_SUCCESS)
742 &QQuick3DPrincipledMaterial::setAttenuationColor,
752 if (
result == aiReturn_SUCCESS)
755 &QQuick3DPrincipledMaterial::setIndexOfRefraction,
759 }
else if (
type == QSSGSceneDesc::Material::RuntimeType::DefaultMaterial) {
760 int shadingModel = 0;
762 result = material->Get(AI_MATKEY_SHADING_MODEL, shadingModel);
764 if (
result == aiReturn_SUCCESS && (shadingModel == aiShadingMode_NoShading))
767 if (
auto diffuseMapTexture = createTextureNode(
source, aiTextureType_DIFFUSE, 0)) {
772 aiColor3D diffuseColor;
773 result = material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor);
774 if (
result == aiReturn_SUCCESS)
778 if (
auto emissiveTexture = createTextureNode(
source, aiTextureType_EMISSIVE, 0))
782 if (
auto specularTexture = createTextureNode(
source, aiTextureType_SPECULAR, 0))
787 result = material->Get(AI_MATKEY_OPACITY, opacity);
788 if (
result == aiReturn_SUCCESS)
792 if (
auto opacityTexture = createTextureNode(
source, aiTextureType_OPACITY, 0))
796 if (
auto bumpTexture = createTextureNode(
source, aiTextureType_HEIGHT, 0)) {
800 result = material->Get(AI_MATKEY_BUMPSCALING, bumpAmount);
801 if (
result == aiReturn_SUCCESS)
806 if (
auto normalTexture = createTextureNode(
source, aiTextureType_NORMALS, 0))
808 }
else if (
type == QSSGSceneDesc::Material::RuntimeType::SpecularGlossyMaterial) {
810 aiColor4D albedoFactor;
811 result =
source.Get(AI_MATKEY_COLOR_DIFFUSE, albedoFactor);
812 if (
result == aiReturn_SUCCESS)
816 if (
auto albedoTexture = createTextureNode(
source, aiTextureType_DIFFUSE, 0)) {
821 if (
auto specularGlossinessTexture = createTextureNode(
source, aiTextureType_SPECULAR, 0)) {
828 aiColor4D specularColorFactor;
829 result =
source.Get(AI_MATKEY_COLOR_SPECULAR, specularColorFactor);
830 if (
result == aiReturn_SUCCESS)
835 ai_real glossinessFactor;
836 result =
source.Get(AI_MATKEY_GLOSSINESS_FACTOR, glossinessFactor);
837 if (
result == aiReturn_SUCCESS)
841 if (
auto normalTexture = createTextureNode(
source, aiTextureType_NORMALS, 0)) {
845 result =
source.Get(AI_MATKEY_GLTF_TEXTURE_SCALE(aiTextureType_NORMALS, 0), normalScale);
846 if (
result == aiReturn_SUCCESS)
852 if (
auto occlusionTexture = createTextureNode(
source, aiTextureType_LIGHTMAP, 0)) {
856 ai_real occlusionAmount;
857 result =
source.Get(AI_MATKEY_GLTF_TEXTURE_STRENGTH(aiTextureType_LIGHTMAP, 0), occlusionAmount);
858 if (
result == aiReturn_SUCCESS)
863 if (
auto emissiveTexture = createTextureNode(
source, aiTextureType_EMISSIVE, 0))
867 aiColor3D emissiveColorFactor;
868 result =
source.Get(AI_MATKEY_COLOR_EMISSIVE, emissiveColorFactor);
869 if (
result == aiReturn_SUCCESS)
876 if (
result == aiReturn_SUCCESS && isDoubleSided)
882 result =
source.Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode);
883 if (
result == aiReturn_SUCCESS) {
903 result =
source.Get(AI_MATKEY_GLTF_ALPHACUTOFF, alphaCutoff);
904 if (
result == aiReturn_SUCCESS)
909 int shadingModel = 0;
910 result =
source.Get(AI_MATKEY_SHADING_MODEL, shadingModel);
911 if (
result == aiReturn_SUCCESS && shadingModel == aiShadingMode_Unlit)
920 ai_real clearcoatFactor = 0.0f;
921 result =
source.Get(AI_MATKEY_CLEARCOAT_FACTOR, clearcoatFactor);
922 if (
result == aiReturn_SUCCESS)
926 float(clearcoatFactor));
931 ai_real clearcoatRoughnessFactor = 0.0f;
932 result =
source.Get(AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR, clearcoatRoughnessFactor);
933 if (
result == aiReturn_SUCCESS)
935 "clearcoatRoughnessAmount",
937 float(clearcoatRoughnessFactor));
941 if (
auto clearcoatTexture = createTextureNode(
source, AI_MATKEY_CLEARCOAT_TEXTURE))
945 if (
auto clearcoatRoughnessTexture = createTextureNode(
source, AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE))
947 "clearcoatRoughnessMap",
949 clearcoatRoughnessTexture);
952 if (
auto clearcoatNormalTexture = createTextureNode(
source, AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE))
960 ai_real transmissionFactor = 0.0f;
961 result =
source.Get(AI_MATKEY_TRANSMISSION_FACTOR, transmissionFactor);
962 if (
result == aiReturn_SUCCESS)
964 "transmissionFactor",
966 float(transmissionFactor));
971 if (
auto transmissionImage = createTextureNode(
source, AI_MATKEY_TRANSMISSION_TEXTURE))
984 ai_real thicknessFactor = 0.0f;
985 result =
source.Get(AI_MATKEY_VOLUME_THICKNESS_FACTOR, thicknessFactor);
986 if (
result == aiReturn_SUCCESS)
992 if (
auto thicknessImage = createTextureNode(
source, AI_MATKEY_VOLUME_THICKNESS_TEXTURE))
998 ai_real attenuationDistance = 0.0f;
999 result =
source.Get(AI_MATKEY_VOLUME_ATTENUATION_DISTANCE, attenuationDistance);
1000 if (
result == aiReturn_SUCCESS)
1002 "attenuationDistance",
1004 float(attenuationDistance));
1009 aiColor3D attenuationColor;
1010 result =
source.Get(AI_MATKEY_VOLUME_ATTENUATION_COLOR, attenuationColor);
1011 if (
result == aiReturn_SUCCESS)
1026 target.runtimeType = (
source.mHorizontalFOV == 0.0f) ? Node::RuntimeType::OrthographicCamera
1027 : Node::RuntimeType::PerspectiveCamera;
1031 aiMatrix4x4 correctionMatrix;
1032 bool needsCorrection =
false;
1039 if (sceneInfo.opt.fbxMode) {
1040 aiMatrix4x4::RotationY(ai_real(
M_PI / 2), correctionMatrix);
1041 needsCorrection =
true;
1043 aiVector3D upQuick3D = aiVector3D(0, 1, 0);
1044 if (
source.mLookAt != aiVector3D(0, 0, -1)) {
1045 aiMatrix4x4 lookAtCorrection;
1046 aiMatrix4x4::FromToMatrix(aiVector3D(0, 0, -1),
source.mLookAt, lookAtCorrection);
1047 correctionMatrix *= lookAtCorrection;
1048 needsCorrection =
true;
1049 upQuick3D *= lookAtCorrection;
1051 if (
source.mUp != upQuick3D) {
1052 aiMatrix4x4 upCorrection;
1053 aiMatrix4x4::FromToMatrix(upQuick3D,
source.mUp, upCorrection);
1054 correctionMatrix = upCorrection * correctionMatrix;
1055 needsCorrection =
true;
1062 if (
target.runtimeType == Node::RuntimeType::PerspectiveCamera) {
1070 if (
target.runtimeType == Node::RuntimeType::PerspectiveCamera) {
1081 const float width =
source.mOrthographicWidth * 2.0f;
1102 aiMatrix4x4 correctionMatrix;
1103 bool needsCorrection =
false;
1104 if (
source.mDirection != aiVector3D(0, 0, 0)) {
1105 if (
source.mDirection != aiVector3D(0, 0, -1)) {
1106 aiMatrix4x4::FromToMatrix(aiVector3D(0, 0, -1),
source.mDirection, correctionMatrix);
1107 needsCorrection =
true;
1112 static const auto asQtLightType = [](aiLightSourceType
type) {
1114 case aiLightSource_AMBIENT:
1116 case aiLightSource_DIRECTIONAL:
1117 return QSSGSceneDesc::Light::RuntimeType::DirectionalLight;
1118 case aiLightSource_POINT:
1119 return QSSGSceneDesc::Light::RuntimeType::PointLight;
1120 case aiLightSource_SPOT:
1121 return QSSGSceneDesc::Light::RuntimeType::SpotLight;
1123 return QSSGSceneDesc::Light::RuntimeType::PointLight;
1141 if (
source.mType == aiLightSource_AMBIENT) {
1147 source.mColorAmbient.g / brightness,
1148 source.mColorAmbient.b / brightness);
1154 source.mColorDiffuse.g / brightness,
1155 source.mColorDiffuse.b / brightness);
1161 const bool isSpot = (
source.mType == aiLightSource_SPOT);
1162 if (
source.mType == aiLightSource_POINT || isSpot) {
1202 QVector<MorphProperty> targets;
1203 const quint32 numMorphTargets =
qMin(8U, mesh.mNumAnimMeshes);
1205 for (
uint i = 0;
i < numMorphTargets; ++
i) {
1206 const auto &animMesh = mesh.mAnimMeshes[
i];
1207 QQuick3DMorphTarget::MorphTargetAttributes mTarget;
1208 if (animMesh->HasPositions())
1210 if (animMesh->HasNormals())
1212 if (animMesh->HasTangentsAndBitangents()) {
1216 targets.push_back(
qMakePair(mTarget, animMesh->mWeight));
1223 if (
source.mNumMeshes == 0)
1226 auto &targetScene =
target.scene;
1227 const auto &srcScene = sceneInfo.scene;
1231 auto &meshStorage = targetScene->meshStorage;
1232 auto &materialMap = sceneInfo.materialMap;
1233 auto &meshMap = sceneInfo.meshMap;
1234 auto &skinMap = sceneInfo.skinMap;
1235 auto &mesh2skin = sceneInfo.mesh2skin;
1237 QVarLengthArray<QSSGSceneDesc::Material *> materials;
1238 materials.reserve(
source.mNumMeshes);
1242 const auto ensureMaterial = [&](
qsizetype materialIndex) {
1244 auto &material = materialMap[materialIndex];
1246 auto targetMat = material.second;
1247 if (targetMat ==
nullptr) {
1248 const aiMaterial *sourceMat = material.first;
1250 auto currentMaterialType = QSSGSceneDesc::Material::RuntimeType::PrincipledMaterial;
1251 ai_real glossinessFactor;
1252 aiReturn
result = sourceMat->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossinessFactor);
1253 if (
result == aiReturn_SUCCESS)
1254 currentMaterialType = QSSGSceneDesc::Material::RuntimeType::SpecularGlossyMaterial;
1259 material.second = targetMat;
1262 Q_ASSERT(targetMat !=
nullptr && material.second !=
nullptr);
1264 Q_ASSERT(srcScene.mMaterials[materialIndex] == material.first);
1265 materials.push_back(targetMat);
1280 const auto combineMeshes = [&](
const aiNode &
source, aiMesh **sceneMeshes) {
1282 const aiMesh &mesh = *sceneMeshes[
source.mMeshes[
i]];
1283 ensureMaterial(mesh.mMaterialIndex);
1284 if (skinIdx == -1 && mesh.HasBones())
1285 skinIdx = mesh2skin[
source.mMeshes[
i]];
1290 const auto createMeshNode = [&](
const aiString &
name) {
1293 sceneInfo.opt.useFloatJointIndices,
1294 sceneInfo.opt.generateMeshLODs,
1295 sceneInfo.opt.lodNormalMergeAngle,
1296 sceneInfo.opt.lodNormalSplitAngle,
1298 meshStorage.push_back(std::move(meshData));
1300 const auto idx = meshStorage.size() - 1;
1307 const bool isMultiMesh = (
source.mNumMeshes > 1);
1310 combineMeshes(
source, srcScene.mMeshes);
1312 meshNode = createMeshNode(
source.mName);
1316 auto &mesh = meshMap[*
source.mMeshes];
1317 meshNode = mesh.second;
1318 if (meshNode ==
nullptr) {
1319 meshes = {mesh.
first};
1320 if (mesh.first->HasBones())
1321 skinIdx = mesh2skin[*
source.mMeshes];
1322 mesh.second = meshNode = createMeshNode(mesh.first->mName);
1325 ensureMaterial(mesh.first->mMaterialIndex);
1326 Q_ASSERT(meshNode !=
nullptr && mesh.second !=
nullptr);
1332 if (skinIdx != -1) {
1333 auto &skin = skinMap[skinIdx];
1348 const aiNode &srcNode,
1353 const auto &srcScene = sceneInfo.
scene;
1354 switch (nodeInfo.type) {
1355 case QSSGSceneDesc::Node::Type::Camera:
1357 const auto &srcType = *srcScene.mCameras[nodeInfo.index];
1365 case QSSGSceneDesc::Node::Type::Light:
1367 const auto &srcType = *srcScene.mLights[nodeInfo.index];
1369 auto targetType =
new QSSGSceneDesc::Light(QSSGSceneDesc::Node::RuntimeType::DirectionalLight);
1375 case QSSGSceneDesc::Node::Type::Model:
1383 case QSSGSceneDesc::Node::Type::Joint:
1392 case QSSGSceneDesc::Node::Type::Transform:
1394 node =
new QSSGSceneDesc::Node(QSSGSceneDesc::Node::Type::Transform, QSSGSceneDesc::Node::RuntimeType::Node);
1410 if (
source.mNumMeshes != 0) {
1412 using It =
decltype(
source.mNumMeshes);
1413 QVector<MorphProperty> morphProps;
1415 const auto &srcScene = sceneInfo.
scene;
1416 const aiMesh &mesh = *srcScene.mMeshes[
source.mMeshes[
i]];
1417 if (mesh.mNumAnimMeshes && mesh.mAnimMeshes) {
1423 if (!morphProps.isEmpty()) {
1425 QVarLengthArray<QSSGSceneDesc::MorphTarget *> morphTargets;
1426 morphTargets.reserve(morphProps.size());
1427 for (
int i = 0,
end = morphProps.size();
i !=
end; ++
i) {
1428 const auto morphProp = morphProps.at(
i);
1434 morphTargets.push_back(morphNode);
1436 if (!animationNodes.isEmpty()) {
1438 const auto aNodeIt = animationNodes.find(morphTargetName.toUtf8());
1439 if (aNodeIt != animationNodes.end() && aNodeIt.value() ==
nullptr)
1440 *aNodeIt = morphNode;
1448 NodeInfo nodeInfo{ 0, QSSGSceneDesc::Node::Type::Transform };
1460 if (!animationNodes.isEmpty()) {
1461 const auto &nodeName =
source.mName;
1462 auto aNodeIt = animationNodes.find(
QByteArray{nodeName.C_Str(),
qsizetype(nodeName.length)});
1463 if (aNodeIt != animationNodes.end() && aNodeIt.value() ==
nullptr)
1468 using It =
decltype (
source.mNumChildren);
1495 value =
it->toObject().value(
"value");
1499 return value.toBool();
1509 value =
it->toObject().value(
"value");
1514 return value.toDouble();
1517#define demonPostProcessPresets ( \
1518 aiProcess_CalcTangentSpace | \
1519 aiProcess_GenSmoothNormals | \
1520 aiProcess_JoinIdenticalVertices | \
1521 aiProcess_ImproveCacheLocality | \
1522 aiProcess_RemoveRedundantMaterials | \
1523 aiProcess_SplitLargeMeshes | \
1524 aiProcess_Triangulate | \
1525 aiProcess_GenUVCoords | \
1526 aiProcess_SortByPType | \
1527 aiProcess_FindDegenerates | \
1528 aiProcess_FindInvalidData | \
1532 aiPostProcessSteps postProcessSteps = aiPostProcessSteps(aiProcess_Triangulate | aiProcess_SortByPType);;
1540 options =
it->toObject();
1543 return postProcessSteps;
1548 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_CalcTangentSpace);
1551 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_JoinIdenticalVertices);
1554 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_GenNormals);
1557 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_GenSmoothNormals);
1560 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_SplitLargeMeshes);
1563 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_PreTransformVertices);
1566 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_ImproveCacheLocality);
1569 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_RemoveRedundantMaterials);
1572 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_FixInfacingNormals);
1575 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_FindDegenerates);
1578 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_FindInvalidData);
1581 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_TransformUVCoords);
1584 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_FindInstances);
1587 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_OptimizeMeshes);
1590 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_OptimizeGraph);
1593 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_DropNormals);
1595 aiComponent removeComponents = aiComponent(0);
1598 removeComponents = aiComponent(removeComponents | aiComponent_NORMALS);
1601 removeComponents = aiComponent(removeComponents | aiComponent_TANGENTS_AND_BITANGENTS);
1604 removeComponents = aiComponent(removeComponents | aiComponent_COLORS);
1607 removeComponents = aiComponent(removeComponents | aiComponent_TEXCOORDS);
1610 removeComponents = aiComponent(removeComponents | aiComponent_BONEWEIGHTS);
1613 removeComponents = aiComponent(removeComponents | aiComponent_ANIMATIONS);
1616 removeComponents = aiComponent(removeComponents | aiComponent_TEXTURES);
1618 if (removeComponents != aiComponent(0)) {
1619 postProcessSteps = aiPostProcessSteps(postProcessSteps | aiProcess_RemoveComponent);
1620 importer->SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, removeComponents);
1624 importer->SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, preservePivots);
1626 return postProcessSteps;
1638 options =
it->toObject();
1641 return sceneOptions;
1645 if (sceneOptions.globalScaleValue == 0.0)
1646 sceneOptions.globalScaleValue = 1.0;
1655 if (sceneOptions.generateLightmapUV) {
1657 sceneOptions.lightmapBaseResolution =
v == 0.0 ? 1024 : int(
v);
1661 if (sceneOptions.generateMeshLODs) {
1663 if (recalculateLODNormals) {
1665 sceneOptions.lodNormalMergeAngle =
qBound(0.0, mergeAngle, 270.0);
1667 sceneOptions.lodNormalSplitAngle =
qBound(0.0, splitAngle, 270.0);
1669 sceneOptions.lodNormalMergeAngle = 0.0;
1670 sceneOptions.lodNormalSplitAngle = 0.0;
1673 return sceneOptions;
1685 if (!sourceFile.exists())
1687 targetScene.sourceDir = sourceFile.path();
1689 std::unique_ptr<Assimp::Importer> importer(
new Assimp::Importer());
1692 aiPostProcessSteps postProcessSteps;
1699 importer->SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
1700 importer->SetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 1);
1702 if (filePath.startsWith(
":"))
1705 auto sourceScene = importer->ReadFile(filePath.toStdString(), postProcessSteps);
1714 targetScene.id = sourceFile.canonicalFilePath();
1717 using It =
decltype(sourceScene->mNumMeshes);
1721 const auto &srcRootNode = *sourceScene->mRootNode;
1727 if (sourceScene->HasLights()) {
1728 for (It
i = 0,
end = sourceScene->mNumLights;
i !=
end; ++
i) {
1729 const auto &
type = *sourceScene->mLights[
i];
1730 if (
auto node = srcRootNode.FindNode(
type.mName))
1731 nodeMap[node] = {
i, NodeInfo::Type::Light };
1735 if (sourceScene->HasCameras()) {
1736 for (It
i = 0,
end = sourceScene->mNumCameras;
i !=
end; ++
i) {
1737 const auto &srcCam = *sourceScene->mCameras[
i];
1738 if (
auto node = srcRootNode.FindNode(srcCam.mName))
1739 nodeMap[node] = {
i, NodeInfo::Type::Camera };
1743 if (sourceScene->HasAnimations()) {
1744 for (It
i = 0,
end = sourceScene->mNumAnimations;
i !=
end; ++
i) {
1745 const auto &srcAnim = *sourceScene->mAnimations[
i];
1746 const auto channelCount = srcAnim.mNumChannels;
1747 for (It cIdx = 0; cIdx != channelCount; ++cIdx) {
1748 const auto &srcChannel = srcAnim.mChannels[cIdx];
1749 const auto &nodeName = srcChannel->mNodeName;
1750 if (nodeName.length > 0) {
1753 if (!animatingNodes.contains(
name))
1754 animatingNodes.insert(
name,
nullptr);
1757 const auto morphChannelCount = srcAnim.mNumMorphMeshChannels;
1758 for (It cIdx = 0; cIdx != morphChannelCount; ++cIdx) {
1759 const auto &srcChannel = srcAnim.mMorphMeshChannels[cIdx];
1760 const auto &nodeName = srcChannel->mName;
1761 if (nodeName.length > 0) {
1762 const auto morphKeys = srcChannel->mKeys;
1763 const auto numMorphTargets =
qMin(morphKeys[0].mNumValuesAndWeights, 8U);
1765 for (It
j = 0;
j < numMorphTargets; ++
j) {
1766 QString morphTargetName(nodeName.C_Str());
1768 animatingNodes.insert(morphTargetName.toUtf8(),
nullptr);
1777 const auto materialCount = sourceScene->mNumMaterials;
1779 materials.reserve(materialCount);
1781 const auto meshCount = sourceScene->mNumMeshes;
1783 meshes.reserve(meshCount);
1785 mesh2skin.reserve(meshCount);
1787 const auto embeddedTextureCount = sourceScene->mNumTextures;
1792 for (It
i = 0;
i != materialCount; ++
i)
1793 materials.push_back({sourceScene->mMaterials[i], nullptr});
1795 for (It
i = 0;
i != meshCount; ++
i) {
1796 meshes.push_back({sourceScene->mMeshes[
i],
nullptr});
1797 if (sourceScene->mMeshes[
i]->HasBones()) {
1798 mesh2skin.push_back(skins.size());
1799 const auto boneCount = sourceScene->mMeshes[
i]->mNumBones;
1800 auto bones = sourceScene->mMeshes[
i]->mBones;
1806 for (It
j = 0;
j != boneCount; ++
j) {
1807 const auto &nodeName = bones[
j]->mName;
1808 if (nodeName.length > 0) {
1809 animatingNodes.insert(
QByteArray{ nodeName.C_Str(),
1815 mesh2skin.push_back(-1);
1819 for (It
i = 0;
i != embeddedTextureCount; ++
i)
1820 embeddedTextures.push_back(
nullptr);
1824 if (!targetScene.root) {
1825 auto root =
new QSSGSceneDesc::Node(QSSGSceneDesc::Node::Type::Transform, QSSGSceneDesc::Node::RuntimeType::Node);
1832 const auto extension = sourceFile.suffix().toLower();
1834 opt.gltfMode =
true;
1838 SceneInfo sceneInfo { *sourceScene, materials, meshes, embeddedTextures,
1839 textureMap, skins, mesh2skin, sourceFile.dir(),
opt };
1842 const auto gscale =
opt.globalScaleValue;
1847 if (sourceScene->mRootNode)
1848 processNode(sceneInfo, *sourceScene->mRootNode, *targetScene.root, nodeMap, animatingNodes);
1850 for (It
i = 0, endI = skins.size();
i != endI; ++
i) {
1851 const auto &skin = skins[
i];
1857 QList<QMatrix4x4> inverseBindPoses;
1858 QVarLengthArray<QSSGSceneDesc::Node *> joints;
1859 joints.reserve(skin.mNumBones);
1860 for (It
j = 0, endJ = skin.mNumBones;
j != endJ; ++
j) {
1861 const auto &bone = *skin.mBones[
j];
1862 const auto &nodeName = bone.mName;
1863 if (nodeName.length > 0) {
1864 auto targetNode = animatingNodes.value(
QByteArray{ nodeName.C_Str(),
qsizetype(nodeName.length) });
1865 joints.push_back(targetNode);
1866 const auto &osMat = bone.mOffsetMatrix;
1867 auto pose =
QMatrix4x4(osMat[0][0], osMat[0][1], osMat[0][2], osMat[0][3],
1868 osMat[1][0], osMat[1][1], osMat[1][2], osMat[1][3],
1869 osMat[2][0], osMat[2][1], osMat[2][2], osMat[2][3],
1870 osMat[3][0], osMat[3][1], osMat[3][2], osMat[3][3]);
1871 inverseBindPoses.push_back(pose);
1878 static const auto fuzzyComparePos = [](
const aiVectorKey *
pos,
const aiVectorKey *prev){
1886 static const auto fuzzyCompareRot = [](
const aiQuatKey *rot,
const aiQuatKey *prev){
1897 Animation targetAnimation;
1898 auto &channels = targetAnimation.channels;
1900 : 1000.0 / srcAnim.mTicksPerSecond;
1901 targetAnimation.framesPerSecond = srcAnim.mTicksPerSecond;
1904 for (It
i = 0,
end = srcAnim.mNumChannels;
i !=
end; ++
i) {
1905 const auto &srcChannel = *srcAnim.mChannels[
i];
1907 const auto &nodeName = srcChannel.mNodeName;
1908 if (nodeName.length > 0) {
1909 const auto aNodeEnd = animatingNodes.cend();
1910 const auto aNodeIt = animatingNodes.constFind(
QByteArray{ nodeName.C_Str(),
qsizetype(nodeName.length) });
1911 if (aNodeIt != aNodeEnd && aNodeIt.value() !=
nullptr) {
1912 auto targetNode = aNodeIt.value();
1915 const auto currentPropertyValue = [targetNode](
const char *propertyName) ->
QVariant {
1916 for (
auto *
p : targetNode->properties) {
1917 if (!
qstrcmp(propertyName,
p->name))
1924 const auto posKeyEnd = srcChannel.mNumPositionKeys;
1926 targetChannel.
targetProperty = Animation::Channel::TargetProperty::Position;
1927 targetChannel.target = targetNode;
1928 const aiVectorKey *prevPos =
nullptr;
1929 for (It posKeyIdx = 0; posKeyIdx != posKeyEnd; ++posKeyIdx) {
1930 const auto &posKey = srcChannel.mPositionKeys[posKeyIdx];
1931 if (fuzzyComparePos(&posKey, prevPos))
1937 const auto isUnchanged = [&targetChannel, currentPropertyValue]() {
1938 if (targetChannel.keys.count() != 1)
1940 auto currentPos = currentPropertyValue(
"position").value<
QVector3D>();
1941 return qFuzzyCompare(targetChannel.keys[0]->value.toVector3D(), currentPos);
1943 if (!targetChannel.keys.isEmpty()) {
1944 if (!isUnchanged()) {
1946 float endTime = float(srcChannel.mPositionKeys[posKeyEnd - 1].mTime) * freq;
1947 if (targetAnimation.length < endTime)
1948 targetAnimation.length = endTime;
1957 const auto rotKeyEnd = srcChannel.mNumRotationKeys;
1959 targetChannel.
targetProperty = Animation::Channel::TargetProperty::Rotation;
1960 targetChannel.target = targetNode;
1961 const aiQuatKey *prevRot =
nullptr;
1962 for (It rotKeyIdx = 0; rotKeyIdx != rotKeyEnd; ++rotKeyIdx) {
1963 const auto &rotKey = srcChannel.mRotationKeys[rotKeyIdx];
1964 if (fuzzyCompareRot(&rotKey, prevRot))
1970 const auto isUnchanged = [&targetChannel, currentPropertyValue]() {
1971 if (targetChannel.keys.count() != 1)
1973 auto currentVal = currentPropertyValue(
"rotation");
1977 if (!targetChannel.keys.isEmpty()) {
1978 if (!isUnchanged()) {
1980 float endTime = float(srcChannel.mRotationKeys[rotKeyEnd - 1].mTime) * freq;
1981 if (targetAnimation.length < endTime)
1982 targetAnimation.length = endTime;
1991 const auto scaleKeyEnd = srcChannel.mNumScalingKeys;
1993 targetChannel.
targetProperty = Animation::Channel::TargetProperty::Scale;
1994 targetChannel.target = targetNode;
1995 const aiVectorKey *prevScale =
nullptr;
1996 for (It scaleKeyIdx = 0; scaleKeyIdx != scaleKeyEnd; ++scaleKeyIdx) {
1997 const auto &scaleKey = srcChannel.mScalingKeys[scaleKeyIdx];
1998 if (fuzzyComparePos(&scaleKey, prevScale))
2001 prevScale = &scaleKey;
2004 const auto isUnchanged = [&targetChannel, currentPropertyValue]() {
2005 if (targetChannel.keys.count() != 1)
2007 auto currentVal = currentPropertyValue(
"scale");
2012 if (!targetChannel.keys.isEmpty()) {
2013 if (!isUnchanged()) {
2015 float endTime = float(srcChannel.mScalingKeys[scaleKeyEnd - 1].mTime) * freq;
2016 if (targetAnimation.length < endTime)
2017 targetAnimation.length = endTime;
2028 for (It
i = 0,
end = srcAnim.mNumMorphMeshChannels;
i !=
end; ++
i) {
2029 const auto &srcMorphChannel = *srcAnim.mMorphMeshChannels[
i];
2030 const QString nodeName(srcMorphChannel.mName.C_Str());
2031 const auto *morphKeys = srcMorphChannel.mKeys;
2032 const auto numMorphTargets =
qMin(morphKeys[0].mNumValuesAndWeights, 8U);
2033 for (It targetId = 0; targetId != numMorphTargets; ++targetId) {
2035 const auto aNodeEnd = animatingNodes.cend();
2036 const auto aNodeIt = animatingNodes.constFind(morphTargetName.toUtf8());
2037 if (aNodeIt != aNodeEnd && aNodeIt.value() !=
nullptr) {
2038 auto targetNode = aNodeIt.value();
2039 const auto weightKeyEnd = srcMorphChannel.mNumKeys;
2041 targetChannel.
targetProperty = Animation::Channel::TargetProperty::Weight;
2042 targetChannel.target = targetNode;
2043 for (It wId = 0; wId != weightKeyEnd; ++wId) {
2044 const auto &weightKey = srcMorphChannel.mKeys[wId];
2046 targetChannel.keys.push_back(animationKey);
2048 if (!targetChannel.keys.isEmpty()) {
2050 float endTime = float(srcMorphChannel.mKeys[weightKeyEnd - 1].mTime) * freq;
2051 if (targetAnimation.length < endTime)
2052 targetAnimation.length = endTime;
2059 if (!targetAnimation.channels.isEmpty())
2060 targetScene.animations.push_back(
new Animation(targetAnimation));
2064 if (sourceScene->HasAnimations()) {
2065 const auto animationCount = sourceScene->mNumAnimations;
2066 targetScene.animations.reserve(animationCount);
2067 for (It
i = 0,
end = animationCount;
i !=
end; ++
i) {
2068 const auto &srcAnim = *sourceScene->mAnimations[
i];
2069 createAnimation(targetScene, srcAnim, animatingNodes);
2102 if (!errorString.isEmpty())
2111 QFile targetFile(targetFileName);
2113 errorString +=
QString(
"Could not write to file: ") + targetFileName;
2118 generatedFiles->append(targetFileName);
#define AI_GLTF_FILTER_NEAREST_MIPMAP_NEAREST
QPair< MorphAttributes, float > MorphProperty
static Q_REQUIRED_RESULT QColor aiColorToQColor(const aiColor3D &color)
#define AI_GLTF_FILTER_NEAREST
#define AI_GLTF_FILTER_NEAREST_MIPMAP_LINEAR
static QSSGSceneDesc::Animation::KeyPosition toAnimationKey(const aiVectorKey &key, qreal freq)
static void processNode(const SceneInfo &sceneInfo, const aiNode &source, QSSGSceneDesc::Node &parent, const NodeMap &nodeMap, AnimationNodeMap &animationNodes)
static qreal getRealOption(const QString &optionName, const QJsonObject &options)
#define AI_GLTF_FILTER_LINEAR_MIPMAP_LINEAR
static QByteArray fromAiString(const aiString &string)
static void setModelProperties(QSSGSceneDesc::Model &target, const aiNode &source, const SceneInfo &sceneInfo)
static void setLightProperties(QSSGSceneDesc::Light &target, const aiLight &source, const aiNode &sourceNode, const SceneInfo &sceneInfo)
static void setMaterialProperties(QSSGSceneDesc::Material &target, const aiMaterial &source, const SceneInfo &sceneInfo, QSSGSceneDesc::Material::RuntimeType type)
static QVector< MorphProperty > getMorphTargetProperties(const aiMesh &mesh)
bool operator==(const TextureInfo &a, const TextureInfo &b)
static bool isEqual(const aiUVTransform &a, const aiUVTransform &b)
QQuick3DMorphTarget::MorphTargetAttributes MorphAttributes
#define AI_GLTF_FILTER_LINEAR
QHash< const aiNode *, NodeInfo > NodeMap
static aiPostProcessSteps processOptions(const QJsonObject &optionsObject, std::unique_ptr< Assimp::Importer > &importer)
static void setNodeProperties(QSSGSceneDesc::Node &target, const aiNode &source, const SceneInfo &sceneInfo, aiMatrix4x4 *transformCorrection)
static QString importImp(const QUrl &url, const QJsonObject &options, QSSGSceneDesc::Scene &targetScene)
static void setTextureProperties(QSSGSceneDesc::Texture &target, const TextureInfo &texInfo, const SceneInfo &sceneInfo)
size_t qHash(const TextureEntry &key, size_t seed)
QHash< QByteArray, QSSGSceneDesc::Node * > AnimationNodeMap
static QSSGSceneDesc::Node * createSceneNode(const NodeInfo &nodeInfo, const aiNode &srcNode, QSSGSceneDesc::Node &parent, const SceneInfo &sceneInfo)
#define demonPostProcessPresets
static SceneInfo::Options processSceneOptions(const QJsonObject &optionsObject)
static void setCameraProperties(QSSGSceneDesc::Camera &target, const aiCamera &source, const aiNode &sourceNode, const SceneInfo &sceneInfo)
static bool checkBooleanOption(const QString &optionName, const QJsonObject &options)
#define AI_GLTF_FILTER_LINEAR_MIPMAP_NEAREST
QString import(const QString &sourceFile, const QDir &savePath, const QJsonObject &options, QStringList *generatedFiles) override
The QColor class provides colors based on RGB, HSV or CMYK values.
static QColor fromRgbF(float r, float g, float b, float a=1.0)
Static convenience function that returns a QColor constructed from the RGB color values,...
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
qint64 pos() const override
\reimp
bool seek(qint64 offset) override
For random-access devices, this function sets the current position to pos, returning true on success,...
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qint64 size() const override
\reimp
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
\inmodule QtCore\reentrant
const_iterator constFind(const QString &key) const
Returns a const iterator pointing to the item with key key in the map.
const_iterator constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
bool isEmpty() const
Returns true if the object is empty.
\inmodule QtCore\reentrant
bool isEmpty() const noexcept
void push_back(parameter_type t)
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
static bool isLocalFile(const QString &url)
Returns true if url is a local file that can be opened with \l{QFile}.
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
The QQuaternion class represents a quaternion consisting of a vector and scalar.
void setBrightness(float brightness)
void setColor(const QColor &color)
void setAmbientColor(const QColor &ambientColor)
void setLighting(QQuick3DDefaultMaterial::Lighting lighting)
void setBumpMap(QQuick3DTexture *bumpMap)
void setEmissiveMap(QQuick3DTexture *emissiveMap)
void setBumpAmount(float bumpAmount)
void setOpacityMap(QQuick3DTexture *opacityMap)
void setNormalMap(QQuick3DTexture *normalMap)
void setOpacity(float opacity)
void setDiffuseMap(QQuick3DTexture *diffuseMap)
void setSpecularMap(QQuick3DTexture *specularMap)
void setDiffuseColor(QColor diffuseColor)
void setIndex(qint32 index)
void setDepthDrawMode(QQuick3DMaterial::DepthDrawMode depthDrawMode)
void setCullMode(QQuick3DMaterial::CullMode cullMode)
QQmlListProperty< QQuick3DMaterial > materials
\qmlproperty List<QtQuick3D::Material> Model::materials
QQmlListProperty< QQuick3DMorphTarget > morphTargets
\qmlproperty List<QtQuick3D::MorphTarget> Model::morphTargets
void setSource(const QUrl &source)
void setAttributes(QQuick3DMorphTarget::MorphTargetAttributes attributes)
void setWeight(float castsShadows)
void setRotation(const QQuaternion &rotation)
void setScale(const QVector3D &scale)
void setPosition(const QVector3D &position)
void setClipFar(float clipFar)
void setClipNear(float clipNear)
void setVerticalMagnification(float horizontalMagnification)
void setHorizontalMagnification(float horizontalMagnification)
void setClipFar(float clipFar)
void setFieldOfViewOrientation(QQuick3DPerspectiveCamera::FieldOfViewOrientation fieldOfViewOrientation)
void setFieldOfView(float fieldOfView)
void setClipNear(float clipNear)
void setConstantFade(float constantFade)
void setQuadraticFade(float quadraticFade)
void setLinearFade(float linearFade)
void setOcclusionMap(QQuick3DTexture *occlusionMap)
void setLighting(QQuick3DPrincipledMaterial::Lighting lighting)
void setBaseColorMap(QQuick3DTexture *baseColorMap)
void setMetalnessMap(QQuick3DTexture *metalnessMap)
void setNormalStrength(float normalStrength)
void setMetalnessChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setEmissiveMap(QQuick3DTexture *emissiveMap)
void setRoughnessChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setAlphaMode(QQuick3DPrincipledMaterial::AlphaMode alphaMode)
void setOcclusionChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setAlphaCutoff(float alphaCutoff)
void setRoughnessMap(QQuick3DTexture *roughnessMap)
void setNormalMap(QQuick3DTexture *normalMap)
void setEmissiveFactor(QVector3D emissiveFactor)
void setRoughness(float roughness)
void setOcclusionAmount(float occlusionAmount)
void setOpacityChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setBaseColor(QColor baseColor)
void setMetalness(float metalnessAmount)
void setInverseBindPoses(const QList< QMatrix4x4 > &poses)
QQmlListProperty< QQuick3DNode > joints
\qmlproperty List<QtQuick3D::Node> Skin::joints
void setEmissiveFactor(const QVector3D &emissiveFactor)
void setAlphaMode(QQuick3DSpecularGlossyMaterial::AlphaMode alphaMode)
void setClearcoatMap(QQuick3DTexture *newClearcoatMap)
void setOcclusionMap(QQuick3DTexture *occlusionMap)
void setClearcoatAmount(float newClearcoatAmount)
void setSpecularColor(const QColor &specular)
void setNormalMap(QQuick3DTexture *normalMap)
void setAlbedoColor(const QColor &albedo)
void setGlossiness(float glossiness)
void setOpacityChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setGlossinessMap(QQuick3DTexture *glossinessMap)
void setTransmissionMap(QQuick3DTexture *newTransmissionMap)
void setEmissiveMap(QQuick3DTexture *emissiveMap)
void setAlphaCutoff(float alphaCutoff)
void setThicknessMap(QQuick3DTexture *newThicknessMap)
void setThicknessFactor(float newThicknessFactor)
void setNormalStrength(float normalStrength)
void setOcclusionChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setAttenuationColor(const QColor &newAttenuationColor)
void setClearcoatRoughnessMap(QQuick3DTexture *newClearcoatRoughnessMap)
void setOcclusionAmount(float occlusionAmount)
void setGlossinessChannel(QQuick3DMaterial::TextureChannelMapping channel)
void setAlbedoMap(QQuick3DTexture *albedoMap)
void setTransmissionFactor(float newTransmissionFactor)
void setSpecularMap(QQuick3DTexture *specularMap)
void setAttenuationDistance(float newAttenuationDistance)
void setClearcoatRoughnessAmount(float newClearcoatRoughnessAmount)
void setLighting(QQuick3DSpecularGlossyMaterial::Lighting lighting)
void setClearcoatNormalMap(QQuick3DTexture *newClearcoatNormalMap)
void setConstantFade(float constantFade)
void setInnerConeAngle(float innerConeAngle)
void setConeAngle(float coneAngle)
void setLinearFade(float linearFade)
void setQuadraticFade(float quadraticFade)
void setPivotV(float pivotV)
void setScaleV(float scaleV)
void setHorizontalTiling(QQuick3DTexture::TilingMode tilingModeHorizontal)
Q_REVISION(6, 7) void setDepthTiling(QQuick3DTexture void setRotationUV(float rotationUV)
void setTextureData(QQuick3DTextureData *textureData)
void setMipFilter(QQuick3DTexture::Filter mipFilter)
void setVerticalTiling(QQuick3DTexture::TilingMode tilingModeVertical)
void setGenerateMipmaps(bool generateMipmaps)
void setIndexUV(int indexUV)
void setPositionU(float positionU)
void setPositionV(float positionV)
void setSource(const QUrl &source)
void setMagFilter(QQuick3DTexture::Filter magFilter)
void setMappingMode(QQuick3DTexture::MappingMode mappingMode)
void setMinFilter(QQuick3DTexture::Filter minFilter)
void setScaleU(float scaleU)
const_iterator cend() const noexcept
const_iterator constEnd() const noexcept
const_iterator constFind(const T &value) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromStdString(const std::string &s)
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
The QVector3D class represents a vector or vertex in 3D space.
constexpr float x() const noexcept
Returns the x coordinate of this point.
The QVector4D class represents a vector or vertex in 4D space.
constexpr float x() const noexcept
Returns the x coordinate of this point.
ResourceIOStream(const char *pFile, const char *pMode)
size_t FileSize() const override
size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override
size_t Tell() const override
size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override
char getOsSeparator() const override
void Close(Assimp::IOStream *pFile) override
bool Exists(const char *pFile) const override
Assimp::IOStream * Open(const char *pFile, const char *pMode) override
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
QSSGMesh::Mesh generateMeshData(const aiScene &scene, const MeshList &meshes, bool useFloatJointIndices, bool generateLevelsOfDetail, float normalMergeAngle, float normalSplitAngle, QString &errorString)
void applyEdit(QSSGSceneDesc::Scene *scene, const QJsonObject &changes)
static void writeQml(const QSSGSceneDesc::Node &transform, OutputContext &output)
QString qmlComponentName(const QString &name)
static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, T &&value)
Q_QUICK3DASSETUTILS_EXPORT void addNode(Node &parent, Node &node)
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
#define Q_REQUIRED_RESULT
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
bool qFuzzyIsNull(qfloat16 f) noexcept
size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
constexpr float qRadiansToDegrees(float radians)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
GLuint GLenum GLenum transform
GLsizei const GLchar *const * path
GLenum GLenum GLenum GLenum mapping
GLenum GLenum GLenum GLenum GLenum scale
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
QLatin1StringView QLatin1String
#define QStringLiteral(str)
#define Q_UNIMPLEMENTED()
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
ReturnedValue read(const char *data)
QT_BEGIN_NAMESPACE typedef uchar * output
QUrl url("example.com")
[constructor-url-reference]
args<< 1<< 2;QJSValue threeAgain=fun.call(args);QString fileName="helloworld.qs";QFile scriptFile(fileName);if(!scriptFile.open(QIODevice::ReadOnly)) QTextStream stream(&scriptFile);QString contents=stream.readAll();scriptFile.close();myEngine.evaluate(contents, fileName);myEngine.globalObject().setProperty("myNumber", 123);...QJSValue myNumberPlusOne=myEngine.evaluate("myNumber + 1");QJSValue result=myEngine.evaluate(...);if(result.isError()) qDebug()<< "Uncaught exception at line"<< result.property("lineNumber").toInt()<< ":"<< result.toString();QPushButton *button=new QPushButton;QJSValue scriptButton=myEngine.newQObject(button);myEngine.globalObject().setProperty("button", scriptButton);myEngine.evaluate("button.checkable = true");qDebug()<< scriptButton.property("checkable").toBool();scriptButton.property("show").call();QJSEngine engine;QObject *myQObject=new QObject();myQObject- setProperty)("dynamicProperty", 3)
TargetProperty targetProperty
bool forceMipMapGeneration
bool designStudioWorkarounds
int lightmapBaseResolution
bool useFloatJointIndices
float lodNormalSplitAngle
float lodNormalMergeAngle
QSSGSceneDesc::Skin * node
QVarLengthArray< QPair< const aiMaterial *, QSSGSceneDesc::Material * > > MaterialMap
QVarLengthArray< skinData > SkinMap
QVarLengthArray< QSSGSceneDesc::TextureData * > EmbeddedTextureMap
QSet< TextureEntry > TextureMap
QVarLengthArray< QPair< const aiMesh *, QSSGSceneDesc::Mesh * > > MeshMap
EmbeddedTextureMap & embeddedTextureMap
QVarLengthArray< qint16 > Mesh2SkinMap
MaterialMap & materialMap
aiTextureMapMode modes[3]