12 #include <assimp/material.h>
13 #ifdef SL_BUILD_WITH_ASSIMP
30 # include <assimp/Importer.hpp>
31 # include <assimp/scene.h>
32 # include <assimp/pbrmaterial.h>
36 struct SLImportKeyframe
39 : translation(nullptr),
45 SLImportKeyframe(aiVectorKey* trans, aiQuatKey* rot, aiVectorKey* scl)
52 aiVectorKey* translation;
56 typedef std::map<SLfloat, SLImportKeyframe> KeyframeMap;
67 KeyframeMap::const_iterator it = keyframes.find(time);
68 aiVector3D result(0, 0, 0);
72 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
74 aiVectorKey* transKey = it->second.translation;
78 result = transKey->mValue;
81 aiVectorKey* frontKey =
nullptr;
82 aiVectorKey* backKey =
nullptr;
85 KeyframeMap::const_reverse_iterator revIt(it);
88 for (; it != keyframes.end(); it++)
90 if (it->second.translation !=
nullptr)
92 backKey = it->second.translation;
98 for (; revIt != keyframes.rend(); revIt++)
100 if (revIt->second.translation !=
nullptr)
102 frontKey = revIt->second.translation;
107 if (frontKey && backKey)
109 SLfloat frontTime = revIt->first;
111 SLfloat t = (time - frontTime) / (backTime - frontTime);
113 result = frontKey->mValue + (t * (backKey->mValue - frontKey->mValue));
117 result = frontKey->mValue;
121 result = backKey->mValue;
125 return SLVec3f(result.x, result.y, result.z);
137 KeyframeMap::const_iterator it = keyframes.find(time);
138 aiVector3D result(1, 1, 1);
142 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
144 aiVectorKey* scaleKey = it->second.scaling;
148 result = scaleKey->mValue;
151 aiVectorKey* frontKey =
nullptr;
152 aiVectorKey* backKey =
nullptr;
155 KeyframeMap::const_reverse_iterator revIt(it);
158 for (; it != keyframes.end(); it++)
160 if (it->second.rotation !=
nullptr)
162 backKey = it->second.scaling;
168 for (; revIt != keyframes.rend(); revIt++)
170 if (revIt->second.rotation !=
nullptr)
172 frontKey = revIt->second.scaling;
177 if (frontKey && backKey)
179 SLfloat frontTime = revIt->first;
181 SLfloat t = (time - frontTime) / (backTime - frontTime);
183 result = frontKey->mValue + (t * (backKey->mValue - frontKey->mValue));
187 result = frontKey->mValue;
191 result = backKey->mValue;
195 return SLVec3f(result.x, result.y, result.z);
207 KeyframeMap::const_iterator it = keyframes.find(time);
208 aiQuaternion result(1, 0, 0, 0);
212 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
214 aiQuatKey* rotKey = it->second.rotation;
218 result = rotKey->mValue;
221 aiQuatKey* frontKey =
nullptr;
222 aiQuatKey* backKey =
nullptr;
225 KeyframeMap::const_reverse_iterator revIt(it);
228 for (; it != keyframes.end(); it++)
230 if (it->second.rotation !=
nullptr)
232 backKey = it->second.rotation;
238 for (; revIt != keyframes.rend(); revIt++)
240 if (revIt->second.rotation !=
nullptr)
242 frontKey = revIt->second.rotation;
247 if (frontKey && backKey)
249 SLfloat frontTime = revIt->first;
251 SLfloat t = (time - frontTime) / (backTime - frontTime);
253 aiQuaternion::Interpolate(result, frontKey->mValue, backKey->mValue, t);
257 result = frontKey->mValue;
261 result = backKey->mValue;
265 return SLQuat4f(result.x, result.y, result.z, result.w);
280 SLbool deleteTexImgAfterBuild,
284 SLbool forceCookTorranceRM,
285 SLProgressHandler* progressHandler,
297 SLstring msg =
"SLAssimpImporter: File not found: " + pathAndFile +
"\n";
307 ai.SetProgressHandler((Assimp::ProgressHandler*)progressHandler);
311 const aiScene* scene = ai.ReadFile(pathAndFile, (
SLuint)flags);
316 SLstring msg =
"Failed to load file: " + pathAndFile +
"\n" + ai.GetErrorString() +
"\n";
322 performInitialScan(scene);
325 loadSkeleton(aniMan,
nullptr, _skeletonRoot);
332 for (
SLint i = 0; i < (
SLint)scene->mNumMaterials; i++)
333 materials.push_back(loadMaterial(assetMgr,
335 scene->mMaterials[i],
341 deleteTexImgAfterBuild));
345 std::map<int, SLMesh*> meshMap;
346 for (
SLint i = 0; i < (
SLint)scene->mNumMeshes; i++)
348 SLMesh* mesh = loadMesh(assetMgr, scene->mMeshes[i]);
352 mesh->
mat(overrideMat);
354 mesh->
mat(materials[scene->mMeshes[i]->mMaterialIndex]);
355 _meshes.push_back(mesh);
359 SL_LOG(
"SLAsssimpImporter::load failed: %s\nin path: %s",
365 _sceneRoot = loadNodesRec(
nullptr, scene->mRootNode, meshMap, loadMeshesOnly);
368 vector<SLAnimation*> animations;
369 for (
SLint i = 0; i < (
SLint)scene->mNumAnimations; i++)
370 animations.push_back(loadAnimation(aniMan, scene->mAnimations[i]));
372 logMessage(
LV_minimal,
"\n---------------------------\n\n");
385 _jointOffsets.clear();
386 _skeletonRoot =
nullptr;
388 _skinnedMeshes.clear();
392 aiNode* SLAssimpImporter::getNodeByName(
const SLstring& name)
394 if (_nodeMap.find(name) != _nodeMap.end())
395 return _nodeMap[name];
403 if (_jointOffsets.find(name) != _jointOffsets.end())
404 return _jointOffsets[name];
410 void SLAssimpImporter::performInitialScan(
const aiScene* scene)
416 logMessage(
LV_detailed,
" Cameras: %d\n", scene->mNumCameras);
417 logMessage(
LV_detailed,
" Lights: %d\n", scene->mNumLights);
418 logMessage(
LV_detailed,
" Meshes: %d\n", scene->mNumMeshes);
419 logMessage(
LV_detailed,
" Materials: %d\n", scene->mNumMaterials);
420 logMessage(
LV_detailed,
" Textures: %d\n", scene->mNumTextures);
421 logMessage(
LV_detailed,
" Animations: %d\n", scene->mNumAnimations);
423 logMessage(
LV_detailed,
"---------------------------------------------\n");
425 findNodes(scene->mRootNode,
" ",
true);
427 logMessage(
LV_detailed,
"---------------------------------------------\n");
428 logMessage(
LV_detailed,
" Searching for skinned meshes and scanning joint names.\n");
435 void SLAssimpImporter::findNodes(aiNode* node,
SLstring padding,
SLbool lastChild)
437 SLstring name = node->mName.C_Str();
441 // rename duplicate node names
442 SLstring renamedString;
443 if (_nodeMap.find(name) != _nodeMap.end())
446 std::ostringstream ss;
447 SLstring lastMatch = name;
448 while (_nodeMap.find(lastMatch) != _nodeMap.end())
452 ss << name << "_" << std::setw( 2 ) << std::setfill( '0' ) << index;
453 lastMatch = ss.str();
458 ss << "(renamed from '" << name << "')";
459 renamedString = ss.str();
464 assert(_nodeMap.find(name) == _nodeMap.end() &&
"Duplicated node name found!");
465 _nodeMap[name] = node;
475 for (
SLuint i = 0; i < node->mNumChildren; i++)
477 findNodes(node->mChildren[i], padding, (i == node->mNumChildren - 1));
484 void SLAssimpImporter::findJoints(
const aiScene* scene)
486 for (
SLuint i = 0; i < scene->mNumMeshes; i++)
488 aiMesh* mesh = scene->mMeshes[i];
489 if (!mesh->HasBones())
493 " Mesh '%s' contains %d joints.\n",
497 for (
SLuint j = 0; j < mesh->mNumBones; j++)
499 SLstring name = mesh->mBones[j]->mName.C_Str();
500 std::map<SLstring, SLMat4f>::iterator it = _jointOffsets.find(name);
501 if (it != _jointOffsets.end())
506 memcpy(&offsetMat, &mesh->mBones[j]->mOffsetMatrix,
sizeof(
SLMat4f));
508 _jointOffsets[name] = offsetMat;
510 logMessage(
LV_detailed,
" Bone '%s' found.\n", name.c_str());
518 void SLAssimpImporter::findSkeletonRoot()
520 _skeletonRoot =
nullptr;
522 if (_jointOffsets.empty())
return;
524 vector<SLVaiNode> ancestorList(_jointOffsets.size());
525 SLint minDepth = INT_MAX;
528 logMessage(
LV_detailed,
"Building joint ancestor lists.\n");
530 auto it = _jointOffsets.begin();
531 for (; it != _jointOffsets.end(); it++, index++)
533 aiNode* node = getNodeByName(it->first);
534 SLVaiNode& list = ancestorList[index];
538 list.insert(list.begin(), node);
539 node = node->mParent;
546 " '%s' ancestor list: ",
558 " '%s' lies at a depth of %d\n",
562 minDepth = std::min(minDepth, (
SLint)list.size());
566 "Bone ancestor lists completed, min depth: %d\n",
570 "Searching ancestor lists for common ancestor.\n");
576 aiNode* lastMatch = ancestorList[0][i];
577 for (
SLuint j = 1; j < ancestorList.size(); j++)
579 if (ancestorList[j][i] != lastMatch)
582 lastMatch = ancestorList[j][i];
588 _skeletonRoot = lastMatch;
590 "Found matching ancestor '%s'.\n",
591 _skeletonRoot->mName.C_Str());
603 _skeletonRoot = ancestorList[0][1];
606 "Determined '%s' to be the skeleton's root node.\n",
607 _skeletonRoot->mName.C_Str());
617 SLstring name = node->mName.C_Str();
621 logMessage(
LV_normal,
"Loading skeleton skeleton.\n");
623 animManager.
skeletons().push_back(_skeleton);
626 joint = _skeleton->createJoint(name, _jointIndex++);
627 _skeleton->rootJoint(joint);
662 for (
SLuint i = 0; i < node->mNumChildren; i++)
663 loadSkeleton(animManager, joint, node->mChildren[i]);
678 SLbool forceCookTorranceRM,
679 SLbool deleteTexImgAfterBuild)
685 aiMat->Get(AI_MATKEY_NAME, matName);
687 if (name.empty()) name =
"Import Material";
693 for (
int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
695 aiTextureType aiTexType = (aiTextureType)tt;
697 if (aiMat->GetTextureCount(aiTexType) > 0)
700 aiTextureMapping mappingType = aiTextureMapping_UV;
703 aiMat->GetTexture(aiTexType,
716 case aiTextureType_DIFFUSE: slTexType =
TT_diffuse;
break;
717 case aiTextureType_NORMALS: slTexType =
TT_normal;
break;
718 case aiTextureType_SPECULAR: slTexType =
TT_specular;
break;
719 case aiTextureType_HEIGHT: slTexType =
TT_height;
break;
720 case aiTextureType_OPACITY: slTexType =
TT_diffuse;
break;
721 case aiTextureType_EMISSIVE: slTexType =
TT_emissive;
break;
722 case aiTextureType_LIGHTMAP:
725 aiString fileRoughnessMetallic;
726 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
727 &fileRoughnessMetallic);
728 SLstring occRghMtlTex = checkFilePath(modelPath,
730 fileRoughnessMetallic.data,
732 SLstring occlusionTex = checkFilePath(modelPath,
736 if (occRghMtlTex == occlusionTex)
749 case aiTextureType_AMBIENT_OCCLUSION:
752 aiString fileRoughnessMetallic;
753 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
754 &fileRoughnessMetallic);
755 SLstring occRghMtlTex = checkFilePath(modelPath,
757 fileRoughnessMetallic.data,
759 SLstring occlusionTex = checkFilePath(modelPath,
763 if (occRghMtlTex == occlusionTex)
769 case aiTextureType_UNKNOWN:
772 aiString fileMetallicRoughness;
773 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
774 &fileMetallicRoughness);
775 SLstring rghMtlTex = checkFilePath(modelPath,
777 fileMetallicRoughness.data,
779 SLstring unknownTex = checkFilePath(modelPath,
783 if (rghMtlTex == unknownTex)
786 aiString fileOcclusion;
787 aiMat->GetTexture(aiTextureType_LIGHTMAP,
790 SLstring occlusionTex = checkFilePath(modelPath,
794 if (rghMtlTex == occlusionTex)
806 SLstring texFile = checkFilePath(modelPath, texturePath, aiPath.data);
821 deleteTexImgAfterBuild);
828 aiColor3D ambient, diffuse, specular, emissive;
829 SLfloat shininess, refracti, reflectivity, color_transparent, transparencyFactor, opacity, roughness = -1, metalness = -1;
830 aiMat->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
831 aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
832 aiMat->Get(AI_MATKEY_COLOR_SPECULAR, specular);
833 aiMat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive);
834 aiMat->Get(AI_MATKEY_SHININESS, shininess);
835 aiMat->Get(AI_MATKEY_REFRACTI, refracti);
836 aiMat->Get(AI_MATKEY_REFLECTIVITY, reflectivity);
837 aiMat->Get(AI_MATKEY_OPACITY, opacity);
838 aiMat->Get(AI_MATKEY_COLOR_TRANSPARENT, color_transparent);
839 aiMat->Get(AI_MATKEY_TRANSPARENCYFACTOR, transparencyFactor);
840 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metalness);
841 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, roughness);
845 if (specular.r > 0.5f &&
852 if (ambientFactor > 0.0f)
854 diffuse.g * ambientFactor,
855 diffuse.b * ambientFactor));
877 if (roughness == -1.0f)
880 if (metalness == -1.0f)
898 SLbool deleteTexImgAfterBuild)
905 for (
auto& i : allLoadedTex)
906 if (i->url() == textureFile)
920 if (deleteTexImgAfterBuild)
941 for (
unsigned int i = 0; i < mesh->mNumFaces; ++i)
943 if (mesh->mFaces[i].mNumIndices == 1) numPoints++;
944 if (mesh->mFaces[i].mNumIndices == 2) numLines++;
945 if (mesh->mFaces[i].mNumIndices == 3) numTriangles++;
946 if (mesh->mFaces[i].mNumIndices > 3) numPolygons++;
950 if ((numTriangles && (numLines || numPoints)) ||
951 (numLines && (numTriangles || numPoints)) ||
952 (numPoints && (numLines || numTriangles)))
960 if (numTriangles && numLines) numLines = 0;
961 if (numTriangles && numPoints) numPoints = 0;
962 if (numLines && numPoints) numPoints = 0;
967 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh contains polygons: %s",
968 mesh->mName.C_Str());
973 if (mesh->mNumVertices == 0)
975 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has no vertices: %s",
976 mesh->mName.C_Str());
981 if (numTriangles == 0 && numLines == 0 && numPoints == 0)
983 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has has no triangles nor lines nor points: %s",
984 mesh->mName.C_Str());
991 SLMesh* m =
new SLMesh(am, name.empty() ?
"Imported Mesh" : name);
1000 m->
P.resize(mesh->mNumVertices);
1003 if (mesh->HasNormals() && numTriangles)
1006 m->
N.resize(m->
P.size());
1010 if (mesh->HasTextureCoords(0) && numTriangles)
1013 m->
UV[0].resize(m->
P.size());
1018 if (mesh->HasTextureCoords(1) && numTriangles)
1021 m->
UV[1].resize(m->
P.size());
1025 for (
SLuint i = 0; i < m->
P.size(); ++i)
1027 m->
P[i].set(mesh->mVertices[i].x,
1028 mesh->mVertices[i].y,
1029 mesh->mVertices[i].z);
1031 m->
N[i].set(mesh->mNormals[i].x,
1032 mesh->mNormals[i].y,
1033 mesh->mNormals[i].z);
1034 if (!m->
UV[0].empty())
1035 m->
UV[0][i].set(mesh->mTextureCoords[0][i].x,
1036 mesh->mTextureCoords[0][i].y);
1037 if (!m->
UV[1].empty())
1038 m->
UV[1][i].set(mesh->mTextureCoords[1][i].x,
1039 mesh->mTextureCoords[1][i].y);
1044 if (m->
P.size() < 65536)
1049 m->
I16.resize((
static_cast<size_t>(numTriangles * 3)));
1050 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1052 if (mesh->mFaces[i].mNumIndices == 3)
1054 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1055 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1056 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[2];
1062 m->
I16.resize((
size_t)numLines * 2);
1063 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1065 if (mesh->mFaces[i].mNumIndices == 2)
1067 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1068 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1074 m->
I16.resize(numPoints);
1075 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1077 if (mesh->mFaces[i].mNumIndices == 1)
1078 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1083 for (
auto i : m->
I16)
1084 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1091 m->
I32.resize((
size_t)numTriangles * 3);
1092 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1094 if (mesh->mFaces[i].mNumIndices == 3)
1096 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1097 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1098 m->
I32[j++] = mesh->mFaces[i].mIndices[2];
1104 m->
I32.resize((
size_t)numLines * 2);
1105 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1107 if (mesh->mFaces[i].mNumIndices == 2)
1109 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1110 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1116 m->
I32.resize((
size_t)numPoints * 1);
1117 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1119 if (mesh->mFaces[i].mNumIndices == 1)
1120 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1125 for (
auto i : m->
I32)
1126 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1129 if (!mesh->HasNormals() && numTriangles)
1133 if (mesh->HasBones())
1135 _skinnedMeshes.push_back(m);
1138 m->
Ji.resize(m->
P.size());
1139 m->
Jw.resize(m->
P.size());
1141 for (
SLuint i = 0; i < mesh->mNumBones; i++)
1143 aiBone* joint = mesh->mBones[i];
1144 SLJoint* slJoint = _skeleton->getJoint(joint->mName.C_Str());
1149 for (
SLuint nW = 0; nW < joint->mNumWeights; nW++)
1152 SLuint vertId = joint->mWeights[nW].mVertexId;
1153 SLfloat weight = joint->mWeights[nW].mWeight;
1156 m->
Jw[vertId].push_back(weight);
1163 mesh->mVertices[vertId].y,
1164 mesh->mVertices[vertId].z));
1169 SL_LOG(
"Failed to load joint of skeleton in SLAssimpImporter::loadMesh: %s",
1170 joint->mName.C_Str());
1182 SLNode* SLAssimpImporter::loadNodesRec(
SLNode* curNode,
1191 curNode =
new SLNode(node->mName.data);
1194 aiMatrix4x4* M = &node->mTransformation;
1197 SLMat4f SLM(M->a1, M->a2, M->a3, M->a4,
1198 M->b1, M->b2, M->b3, M->b4,
1199 M->c1, M->c2, M->c3, M->c4,
1200 M->d1, M->d2, M->d3, M->d4);
1207 if (node->mNumMeshes > 1)
1209 for (
SLuint i = 0; i < node->mNumMeshes; ++i)
1212 if (meshes.count((
SLint)node->mMeshes[i]))
1214 SLstring nodeMeshName = node->mName.data;
1215 nodeMeshName +=
"-";
1216 nodeMeshName += meshes[(
SLint)node->mMeshes[i]]->name();
1223 else if (node->mNumMeshes == 1)
1226 if (meshes.count((
SLint)node->mMeshes[0]))
1231 for (
SLuint i = 0; i < node->mNumChildren; i++)
1234 if (node->mChildren[i] == _skeletonRoot)
1238 if (!loadMeshesOnly || aiNodeHasMesh(node->mChildren[i]))
1240 SLNode* child =
new SLNode(node->mChildren[i]->mName.data);
1242 loadNodesRec(child, node->mChildren[i], meshes);
1257 SLfloat animTicksPerSec = (anim->mTicksPerSecond < 0.0001f)
1259 : (
SLfloat)anim->mTicksPerSecond;
1260 SLfloat animDuration = (
SLfloat)anim->mDuration / animTicksPerSec;
1262 if (anim->mName.length > 0)
1263 animName = anim->mName.C_Str();
1266 logMessage(
LV_minimal,
"\nLoading animation %s\n", animName.c_str());
1267 logMessage(
LV_normal,
" Duration(seconds): %f \n", animDuration);
1268 logMessage(
LV_normal,
" Duration(ticks): %f \n", anim->mDuration);
1269 logMessage(
LV_normal,
" Ticks per second: %f \n", animTicksPerSec);
1270 logMessage(
LV_normal,
" Num channels: %d\n", anim->mNumChannels);
1273 if (!_skinnedMeshes.empty())
1274 assert(_skeleton !=
nullptr &&
"The skeleton wasn't imported correctly.");
1279 result = _skeleton->createAnimation(animManager, animName, animDuration);
1283 _animationNamesMap.push_back(result);
1286 SLbool isSkeletonAnim =
false;
1287 for (
SLuint i = 0; i < anim->mNumChannels; i++)
1289 aiNodeAnim* channel = anim->mChannels[i];
1292 SLstring nodeName = channel->mNodeName.C_Str();
1295 SLbool isJointNode = (affectedNode ==
nullptr);
1302 if (!isJointNode && isSkeletonAnim)
1306 if (_skeletonRoot && !affectedNode)
1308 isSkeletonAnim =
true;
1309 SLJoint* affectedJoint = _skeleton->getJoint(nodeName);
1310 if (affectedJoint ==
nullptr)
1313 id = affectedJoint->
id();
1343 affectedJoint->
om(prevOM);
1347 logMessage(
LV_normal,
"\n Channel %d %s", i, (isJointNode) ?
"(joint animation)\n" :
"\n");
1348 logMessage(
LV_normal,
" Affected node: %s\n", channel->mNodeName.C_Str());
1349 logMessage(
LV_detailed,
" Num position keys: %d\n", channel->mNumPositionKeys);
1350 logMessage(
LV_detailed,
" Num rotation keys: %d\n", channel->mNumRotationKeys);
1351 logMessage(
LV_detailed,
" Num scaling keys: %d\n", channel->mNumScalingKeys);
1357 if (affectedNode && !isSkeletonAnim)
1362 KeyframeMap keyframes;
1365 for (
SLuint iK = 0; iK < channel->mNumPositionKeys; iK++)
1367 SLfloat time = (
SLfloat)channel->mPositionKeys[iK].mTime / animTicksPerSec;
1368 keyframes[time] = SLImportKeyframe(&channel->mPositionKeys[iK],
nullptr,
nullptr);
1372 for (
SLuint iK = 0; iK < channel->mNumRotationKeys; iK++)
1374 SLfloat time = (
SLfloat)channel->mRotationKeys[iK].mTime / animTicksPerSec;
1376 if (keyframes.find(time) == keyframes.end())
1377 keyframes[time] = SLImportKeyframe(
nullptr, &channel->mRotationKeys[iK],
nullptr);
1381 assert(keyframes[time].rotation ==
nullptr &&
"There were two rotation keys assigned to the same timestamp.");
1382 keyframes[time].rotation = &channel->mRotationKeys[iK];
1387 for (
SLuint iK = 0; iK < channel->mNumScalingKeys; iK++)
1389 SLfloat time = (
SLfloat)channel->mScalingKeys[iK].mTime / animTicksPerSec;
1391 if (keyframes.find(time) == keyframes.end())
1392 keyframes[time] = SLImportKeyframe(
nullptr,
nullptr, &channel->mScalingKeys[iK]);
1396 assert(keyframes[time].scaling ==
nullptr &&
"There were two scaling keys assigned to the same timestamp.");
1397 keyframes[time].scaling = &channel->mScalingKeys[iK];
1401 logMessage(
LV_normal,
" Found %d distinct keyframe timestamp(s).\n", keyframes.size());
1403 for (
auto it : keyframes)
1406 kf->
translation(getTranslation(it.first, keyframes));
1407 kf->
rotation(getRotation(it.first, keyframes));
1408 kf->
scale(getScaling(it.first, keyframes));
1412 "\n Generating keyframe at time '%.2f'\n",
1415 " Translation: (%.2f, %.2f, %.2f) %s\n",
1419 (it.second.translation !=
nullptr) ?
"imported" :
"generated");
1421 " Rotation: (%.2f, %.2f, %.2f, %.2f) %s\n",
1426 (it.second.rotation !=
nullptr) ?
"imported" :
"generated");
1428 " Scale: (%.2f, %.2f, %.2f) %s\n",
1432 (it.second.scaling !=
nullptr) ?
"imported" :
"generated");
1450 SLbool SLAssimpImporter::aiNodeHasMesh(aiNode* node)
1452 if (node->mNumMeshes > 0)
return true;
1454 for (
SLuint i = 0; i < node->mNumChildren; i++)
1455 if (node->mChildren[i]->mNumMeshes > 0)
1456 return aiNodeHasMesh(node->mChildren[i]);
1475 SLstring pathFile = modelPath + aiTexFile;
1489 SL_LOG_DEBUG(
"**** WARNING ****: SLAssimpImporter: Texture file not found: %s from model %s",
1494 return texturePath +
"TexNotFound.png";
#define PROFILE_FUNCTION()
#define SL_LOG_DEBUG(...)
#define SL_WARN_MSG(message)
#define SL_EXIT_MSG(message)
SLTextureType
Texture type enumeration & their filename appendix for auto type detection.
vector< SLGLTexture * > SLVGLTexture
STL vector of SLGLTexture pointers.
#define SL_ANISOTROPY_MAX
std::map< int, SLMesh * > SLMeshMap
SLMat4< SLfloat > SLMat4f
vector< SLMaterial * > SLVMaterial
STL vector of material pointers.
SLQuat4< SLfloat > SLQuat4f
SLVec3< SLfloat > SLVec3f
SLVec4< SLfloat > SLCol4f
SLAnimManager is the central class for all animation handling.
SLVSkeleton & skeletons()
SLVstring & animationNames()
SLAnimation * createNodeAnimation(SLfloat duration)
SLAnimSkeleton keeps track of a skeletons joints and animations.
SLAnimation is the base container for all animation data.
SLNodeAnimTrack * createNodeAnimTrack()
Toplevel holder of the assets meshes, materials, textures and shaders.
SLVGLTexture & textures()
Texture object for OpenGL texturing.
void deleteImageAfterBuild(SLbool delImg)
If deleteImageAfterBuild is set to true you won't be able to ray trace the scene.
Specialized SLNode that represents a single joint (or bone) in a skeleton.
void offsetMat(const SLMat4f &mat)
void calcMaxRadius(const SLVec3f &vec)
SLJoint * createChild(SLuint id)
void transpose()
Sets the transposed matrix by swaping around the main diagonal.
SLMat4< T > inverted() const
Computes the inverse of a 4x4 non-singular matrix.
Defines a standard CG material with textures and a shader program.
void reflectionModel(SLReflectionModel rm)
void specular(const SLCol4f &spec)
void skybox(SLSkybox *sb)
void diffuse(const SLCol4f &diff)
void addTexture(SLGLTexture *texture)
Adds the passed texture to the equivalent texture type vector.
void shininess(SLfloat shin)
void ambient(const SLCol4f &ambi)
void roughness(SLfloat r)
SLbool hasTextureType(SLTextureType tt)
void emissive(const SLCol4f &emis)
void metalness(SLfloat m)
An SLMesh object is a triangulated mesh, drawn with one draw call.
SLVuint I32
Vector of vertex indices 32 bit.
SLGLPrimitiveType primitive() const
SLVushort I16
Vector of vertex indices 16 bit.
virtual void calcNormals()
SLMesh::calcNormals recalculates vertex normals for triangle meshes.
SLVVec3f N
Vector for vertex normals (opt.) layout (location = 1)
SLVVec2f UV[2]
Array of 2 Vectors for tex. coords. (opt.) layout (location = 2)
SLVVuchar Ji
2D Vector of per vertex joint ids (opt.) layout (location = 6)
SLVVfloat Jw
2D Vector of per vertex joint weights (opt.) layout (location = 7)
const SLAnimSkeleton * skeleton() const
SLVVec3f P
Vector for vertex positions layout (location = 0)
Specialized animation track for node animations.
void animatedNode(SLNode *target)
SLTransformKeyframe * createNodeKeyframe(SLfloat time)
SLNode represents a node in a hierarchical scene graph.
T * find(const SLstring &name="", SLbool findRecursive=true)
void addChild(SLNode *child)
const SLMat4f & updateAndGetWM() const
virtual void addMesh(SLMesh *mesh)
void om(const SLMat4f &mat)
Skybox node class with a SLBox mesh.
bool exists(std::string path, SLIOStreamKind kind)
Checks whether a given file exists.
void clear(std::string path)
string getFileNameWOExt(const string &pathFilename)
Returns the filename without extension.
string getFileName(const string &pathFilename)
Returns the filename of path-filename string.
string getPath(const string &pathFilename)
Returns the path w. '\' of path-filename string.
bool startsWithString(const string &container, const string &startStr)
Return true if the container string starts with the startStr.
bool endsWithString(const string &container, const string &endStr)
Return true if the container string ends with the endStr.