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);
73 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
75 aiVectorKey* transKey = it->second.translation;
79 result = transKey->mValue;
82 aiVectorKey* frontKey =
nullptr;
83 aiVectorKey* backKey =
nullptr;
86 KeyframeMap::const_reverse_iterator revIt(it);
89 for (; it != keyframes.end(); it++)
91 if (it->second.translation !=
nullptr)
93 backKey = it->second.translation;
99 for (; revIt != keyframes.rend(); revIt++)
101 if (revIt->second.translation !=
nullptr)
103 frontKey = revIt->second.translation;
108 if (frontKey && backKey)
110 SLfloat frontTime = revIt->first;
112 SLfloat t = (time - frontTime) / (backTime - frontTime);
114 result = frontKey->mValue + (t * (backKey->mValue - frontKey->mValue));
118 result = frontKey->mValue;
122 result = backKey->mValue;
126 return SLVec3f(result.x, result.y, result.z);
138 KeyframeMap::const_iterator it = keyframes.find(time);
139 aiVector3D result(1, 1, 1);
143 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
145 aiVectorKey* scaleKey = it->second.scaling;
149 result = scaleKey->mValue;
152 aiVectorKey* frontKey =
nullptr;
153 aiVectorKey* backKey =
nullptr;
156 KeyframeMap::const_reverse_iterator revIt(it);
159 for (; it != keyframes.end(); it++)
161 if (it->second.rotation !=
nullptr)
163 backKey = it->second.scaling;
169 for (; revIt != keyframes.rend(); revIt++)
171 if (revIt->second.rotation !=
nullptr)
173 frontKey = revIt->second.scaling;
178 if (frontKey && backKey)
180 SLfloat frontTime = revIt->first;
182 SLfloat t = (time - frontTime) / (backTime - frontTime);
184 result = frontKey->mValue + (t * (backKey->mValue - frontKey->mValue));
188 result = frontKey->mValue;
192 result = backKey->mValue;
196 return SLVec3f(result.x, result.y, result.z);
208 KeyframeMap::const_iterator it = keyframes.find(time);
209 aiQuaternion result(1, 0, 0, 0);
213 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
215 aiQuatKey* rotKey = it->second.rotation;
219 result = rotKey->mValue;
222 aiQuatKey* frontKey =
nullptr;
223 aiQuatKey* backKey =
nullptr;
226 KeyframeMap::const_reverse_iterator revIt(it);
229 for (; it != keyframes.end(); it++)
231 if (it->second.rotation !=
nullptr)
233 backKey = it->second.rotation;
239 for (; revIt != keyframes.rend(); revIt++)
241 if (revIt->second.rotation !=
nullptr)
243 frontKey = revIt->second.rotation;
248 if (frontKey && backKey)
250 SLfloat frontTime = revIt->first;
252 SLfloat t = (time - frontTime) / (backTime - frontTime);
254 aiQuaternion::Interpolate(result, frontKey->mValue, backKey->mValue, t);
258 result = frontKey->mValue;
262 result = backKey->mValue;
266 return SLQuat4f(result.x, result.y, result.z, result.w);
281 SLbool deleteTexImgAfterBuild,
285 SLbool forceCookTorranceRM,
286 SLProgressHandler* progressHandler,
298 SLstring msg =
"SLAssimpImporter: File not found: " + pathAndFile +
"\n";
308 ai.SetProgressHandler((Assimp::ProgressHandler*)progressHandler);
312 const aiScene* scene = ai.ReadFile(pathAndFile, (
SLuint)flags);
317 SLstring msg =
"Failed to load file: " + pathAndFile +
"\n" +
318 ai.GetErrorString() +
"\n";
324 performInitialScan(scene);
327 loadSkeleton(aniMan,
nullptr, _skeletonRoot);
334 for (
SLint i = 0; i < (
SLint)scene->mNumMaterials; i++)
335 materials.push_back(loadMaterial(assetMgr,
337 scene->mMaterials[i],
343 deleteTexImgAfterBuild));
347 std::map<int, SLMesh*> meshMap;
348 for (
SLint i = 0; i < (
SLint)scene->mNumMeshes; i++)
350 SLMesh* mesh = loadMesh(assetMgr, scene->mMeshes[i]);
354 mesh->
mat(overrideMat);
356 mesh->
mat(materials[scene->mMeshes[i]->mMaterialIndex]);
357 _meshes.push_back(mesh);
361 SL_LOG(
"SLAsssimpImporter::load failed: %s\nin path: %s",
367 _sceneRoot = loadNodesRec(
nullptr, scene->mRootNode, meshMap, loadMeshesOnly);
370 vector<SLAnimation*> animations;
371 for (
SLint i = 0; i < (
SLint)scene->mNumAnimations; i++)
372 animations.push_back(loadAnimation(aniMan, scene->mAnimations[i]));
374 logMessage(
LV_minimal,
"\n---------------------------\n\n");
387 _jointOffsets.clear();
388 _skeletonRoot =
nullptr;
390 _skinnedMeshes.clear();
394 aiNode* SLAssimpImporter::getNodeByName(
const SLstring& name)
396 if (_nodeMap.find(name) != _nodeMap.end())
397 return _nodeMap[name];
405 if (_jointOffsets.find(name) != _jointOffsets.end())
406 return _jointOffsets[name];
412 void SLAssimpImporter::performInitialScan(
const aiScene* scene)
418 logMessage(
LV_detailed,
" Cameras: %d\n", scene->mNumCameras);
419 logMessage(
LV_detailed,
" Lights: %d\n", scene->mNumLights);
420 logMessage(
LV_detailed,
" Meshes: %d\n", scene->mNumMeshes);
421 logMessage(
LV_detailed,
" Materials: %d\n", scene->mNumMaterials);
422 logMessage(
LV_detailed,
" Textures: %d\n", scene->mNumTextures);
423 logMessage(
LV_detailed,
" Animations: %d\n", scene->mNumAnimations);
425 logMessage(
LV_detailed,
"---------------------------------------------\n");
427 findNodes(scene->mRootNode,
" ",
true);
429 logMessage(
LV_detailed,
"---------------------------------------------\n");
430 logMessage(
LV_detailed,
" Searching for skinned meshes and scanning joint names.\n");
437 void SLAssimpImporter::findNodes(aiNode* node,
SLstring padding,
SLbool lastChild)
439 SLstring name = node->mName.C_Str();
443 // rename duplicate node names
444 SLstring renamedString;
445 if (_nodeMap.find(name) != _nodeMap.end())
448 std::ostringstream ss;
449 SLstring lastMatch = name;
450 while (_nodeMap.find(lastMatch) != _nodeMap.end())
454 ss << name << "_" << std::setw( 2 ) << std::setfill( '0' ) << index;
455 lastMatch = ss.str();
460 ss << "(renamed from '" << name << "')";
461 renamedString = ss.str();
466 assert(_nodeMap.find(name) == _nodeMap.end() &&
"Duplicated node name found!");
467 _nodeMap[name] = node;
477 for (
SLuint i = 0; i < node->mNumChildren; i++)
479 findNodes(node->mChildren[i], padding, (i == node->mNumChildren - 1));
486 void SLAssimpImporter::findJoints(
const aiScene* scene)
488 for (
SLuint i = 0; i < scene->mNumMeshes; i++)
490 aiMesh* mesh = scene->mMeshes[i];
491 if (!mesh->HasBones())
495 " Mesh '%s' contains %d joints.\n",
499 for (
SLuint j = 0; j < mesh->mNumBones; j++)
501 SLstring name = mesh->mBones[j]->mName.C_Str();
502 std::map<SLstring, SLMat4f>::iterator it = _jointOffsets.find(name);
503 if (it != _jointOffsets.end())
518 _jointOffsets[name] = offsetMat;
520 logMessage(
LV_detailed,
" Bone '%s' found.\n", name.c_str());
528 void SLAssimpImporter::findSkeletonRoot()
530 _skeletonRoot =
nullptr;
532 if (_jointOffsets.empty())
return;
534 vector<SLVaiNode> ancestorList(_jointOffsets.size());
535 SLint minDepth = INT_MAX;
538 logMessage(
LV_detailed,
"Building joint ancestor lists.\n");
540 auto it = _jointOffsets.begin();
541 for (; it != _jointOffsets.end(); it++, index++)
543 aiNode* node = getNodeByName(it->first);
544 SLVaiNode& list = ancestorList[index];
548 list.insert(list.begin(), node);
549 node = node->mParent;
556 " '%s' ancestor list: ",
568 " '%s' lies at a depth of %d\n",
572 minDepth = std::min(minDepth, (
SLint)list.size());
576 "Bone ancestor lists completed, min depth: %d\n",
580 "Searching ancestor lists for common ancestor.\n");
586 aiNode* lastMatch = ancestorList[0][i];
587 for (
SLuint j = 1; j < ancestorList.size(); j++)
589 if (ancestorList[j][i] != lastMatch)
592 lastMatch = ancestorList[j][i];
598 _skeletonRoot = lastMatch;
600 "Found matching ancestor '%s'.\n",
601 _skeletonRoot->mName.C_Str());
613 _skeletonRoot = ancestorList[0][1];
616 "Determined '%s' to be the skeleton's root node.\n",
617 _skeletonRoot->mName.C_Str());
627 SLstring name = node->mName.C_Str();
631 logMessage(
LV_normal,
"Loading skeleton skeleton.\n");
633 animManager.
skeletons().push_back(_skeleton);
636 joint = _skeleton->createJoint(name, _jointIndex++);
637 _skeleton->rootJoint(joint);
672 for (
SLuint i = 0; i < node->mNumChildren; i++)
673 loadSkeleton(animManager, joint, node->mChildren[i]);
688 SLbool forceCookTorranceRM,
689 SLbool deleteTexImgAfterBuild)
695 aiMat->Get(AI_MATKEY_NAME, matName);
697 if (name.empty()) name =
"Import Material";
703 for (
int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
705 aiTextureType aiTexType = (aiTextureType)tt;
707 if (aiMat->GetTextureCount(aiTexType) > 0)
710 aiTextureMapping mappingType = aiTextureMapping_UV;
713 aiMat->GetTexture(aiTexType,
726 case aiTextureType_DIFFUSE: slTexType =
TT_diffuse;
break;
727 case aiTextureType_NORMALS: slTexType =
TT_normal;
break;
728 case aiTextureType_SPECULAR: slTexType =
TT_specular;
break;
729 case aiTextureType_HEIGHT: slTexType =
TT_height;
break;
730 case aiTextureType_OPACITY: slTexType =
TT_diffuse;
break;
731 case aiTextureType_EMISSIVE: slTexType =
TT_emissive;
break;
732 case aiTextureType_LIGHTMAP:
735 aiString fileRoughnessMetallic;
736 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
737 &fileRoughnessMetallic);
738 SLstring occRghMtlTex = checkFilePath(modelPath,
740 fileRoughnessMetallic.data,
742 SLstring occlusionTex = checkFilePath(modelPath,
746 if (occRghMtlTex == occlusionTex)
759 case aiTextureType_AMBIENT_OCCLUSION:
762 aiString fileRoughnessMetallic;
763 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
764 &fileRoughnessMetallic);
765 SLstring occRghMtlTex = checkFilePath(modelPath,
767 fileRoughnessMetallic.data,
769 SLstring occlusionTex = checkFilePath(modelPath,
773 if (occRghMtlTex == occlusionTex)
779 case aiTextureType_UNKNOWN:
782 aiString fileMetallicRoughness;
783 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
784 &fileMetallicRoughness);
785 SLstring rghMtlTex = checkFilePath(modelPath,
787 fileMetallicRoughness.data,
789 SLstring unknownTex = checkFilePath(modelPath,
793 if (rghMtlTex == unknownTex)
796 aiString fileOcclusion;
797 aiMat->GetTexture(aiTextureType_LIGHTMAP,
800 SLstring occlusionTex = checkFilePath(modelPath,
804 if (rghMtlTex == occlusionTex)
816 SLstring texFile = checkFilePath(modelPath, texturePath, aiPath.data);
831 deleteTexImgAfterBuild);
838 aiColor3D ambient, diffuse, specular, emissive;
839 SLfloat shininess, refracti, reflectivity, transparencyFactor, opacity, roughness = -1, metalness = -1;
840 aiMat->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
841 aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
842 aiMat->Get(AI_MATKEY_COLOR_SPECULAR, specular);
843 aiMat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive);
844 aiMat->Get(AI_MATKEY_SHININESS, shininess);
845 aiMat->Get(AI_MATKEY_REFRACTI, refracti);
846 aiMat->Get(AI_MATKEY_REFLECTIVITY, reflectivity);
847 aiMat->Get(AI_MATKEY_OPACITY, opacity);
848 aiMat->Get(AI_MATKEY_TRANSPARENCYFACTOR, transparencyFactor);
849 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metalness);
850 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, roughness);
854 if (specular.r > 0.5f &&
861 if (ambientFactor > 0.0f)
863 diffuse.g * ambientFactor,
864 diffuse.b * ambientFactor));
886 if (roughness == -1.0f)
889 if (metalness == -1.0f)
907 SLbool deleteTexImgAfterBuild)
914 for (
auto& i : allLoadedTex)
915 if (i->url() == textureFile)
929 if (deleteTexImgAfterBuild)
950 for (
unsigned int i = 0; i < mesh->mNumFaces; ++i)
952 if (mesh->mFaces[i].mNumIndices == 1) numPoints++;
953 if (mesh->mFaces[i].mNumIndices == 2) numLines++;
954 if (mesh->mFaces[i].mNumIndices == 3) numTriangles++;
955 if (mesh->mFaces[i].mNumIndices > 3) numPolygons++;
959 if ((numTriangles && (numLines || numPoints)) ||
960 (numLines && (numTriangles || numPoints)) ||
961 (numPoints && (numLines || numTriangles)))
969 if (numTriangles && numLines) numLines = 0;
970 if (numTriangles && numPoints) numPoints = 0;
971 if (numLines && numPoints) numPoints = 0;
976 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh contains polygons: %s",
977 mesh->mName.C_Str());
982 if (mesh->mNumVertices == 0)
984 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has no vertices: %s",
985 mesh->mName.C_Str());
990 if (numTriangles == 0 && numLines == 0 && numPoints == 0)
992 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has has no triangles nor lines nor points: %s",
993 mesh->mName.C_Str());
1000 SLMesh* m =
new SLMesh(am, name.empty() ?
"Imported Mesh" : name);
1009 m->
P.resize(mesh->mNumVertices);
1012 if (mesh->HasNormals() && numTriangles)
1015 m->
N.resize(m->
P.size());
1019 if (mesh->HasTextureCoords(0) && numTriangles)
1022 m->
UV[0].resize(m->
P.size());
1027 if (mesh->HasTextureCoords(1) && numTriangles)
1030 m->
UV[1].resize(m->
P.size());
1034 for (
SLuint i = 0; i < m->
P.size(); ++i)
1036 m->
P[i].set(mesh->mVertices[i].x,
1037 mesh->mVertices[i].y,
1038 mesh->mVertices[i].z);
1040 m->
N[i].set(mesh->mNormals[i].x,
1041 mesh->mNormals[i].y,
1042 mesh->mNormals[i].z);
1043 if (!m->
UV[0].empty())
1044 m->
UV[0][i].set(mesh->mTextureCoords[0][i].x,
1045 mesh->mTextureCoords[0][i].y);
1046 if (!m->
UV[1].empty())
1047 m->
UV[1][i].set(mesh->mTextureCoords[1][i].x,
1048 mesh->mTextureCoords[1][i].y);
1053 if (m->
P.size() < 65536)
1058 m->
I16.resize((
static_cast<size_t>(numTriangles * 3)));
1059 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1061 if (mesh->mFaces[i].mNumIndices == 3)
1063 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1064 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1065 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[2];
1071 m->
I16.resize((
size_t)numLines * 2);
1072 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1074 if (mesh->mFaces[i].mNumIndices == 2)
1076 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1077 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1083 m->
I16.resize(numPoints);
1084 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1086 if (mesh->mFaces[i].mNumIndices == 1)
1087 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1092 for (
auto i : m->
I16)
1093 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1100 m->
I32.resize((
size_t)numTriangles * 3);
1101 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1103 if (mesh->mFaces[i].mNumIndices == 3)
1105 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1106 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1107 m->
I32[j++] = mesh->mFaces[i].mIndices[2];
1113 m->
I32.resize((
size_t)numLines * 2);
1114 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1116 if (mesh->mFaces[i].mNumIndices == 2)
1118 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1119 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1125 m->
I32.resize((
size_t)numPoints * 1);
1126 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1128 if (mesh->mFaces[i].mNumIndices == 1)
1129 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1134 for (
auto i : m->
I32)
1135 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1138 if (!mesh->HasNormals() && numTriangles)
1142 if (mesh->HasBones())
1144 _skinnedMeshes.push_back(m);
1147 m->
Ji.resize(m->
P.size());
1148 m->
Jw.resize(m->
P.size());
1150 for (
SLuint i = 0; i < mesh->mNumBones; i++)
1152 aiBone* joint = mesh->mBones[i];
1153 SLJoint* slJoint = _skeleton->getJoint(joint->mName.C_Str());
1158 for (
SLuint nW = 0; nW < joint->mNumWeights; nW++)
1161 SLuint vertId = joint->mWeights[nW].mVertexId;
1162 SLfloat weight = joint->mWeights[nW].mWeight;
1165 m->
Jw[vertId].push_back(weight);
1172 mesh->mVertices[vertId].y,
1173 mesh->mVertices[vertId].z));
1178 SL_LOG(
"Failed to load joint of skeleton in SLAssimpImporter::loadMesh: %s",
1179 joint->mName.C_Str());
1191 SLNode* SLAssimpImporter::loadNodesRec(
SLNode* curNode,
1200 curNode =
new SLNode(node->mName.data);
1203 aiMatrix4x4* M = &node->mTransformation;
1206 SLMat4f SLM(M->a1, M->a2, M->a3, M->a4,
1207 M->b1, M->b2, M->b3, M->b4,
1208 M->c1, M->c2, M->c3, M->c4,
1209 M->d1, M->d2, M->d3, M->d4);
1216 if (node->mNumMeshes > 1)
1218 for (
SLuint i = 0; i < node->mNumMeshes; ++i)
1221 if (meshes.count((
SLint)node->mMeshes[i]))
1223 SLstring nodeMeshName = node->mName.data;
1224 nodeMeshName +=
"-";
1225 nodeMeshName += meshes[(
SLint)node->mMeshes[i]]->name();
1232 else if (node->mNumMeshes == 1)
1235 if (meshes.count((
SLint)node->mMeshes[0]))
1240 for (
SLuint i = 0; i < node->mNumChildren; i++)
1243 if (node->mChildren[i] == _skeletonRoot)
1247 if (!loadMeshesOnly || aiNodeHasMesh(node->mChildren[i]))
1249 SLNode* child =
new SLNode(node->mChildren[i]->mName.data);
1251 loadNodesRec(child, node->mChildren[i], meshes);
1266 SLfloat animTicksPerSec = (anim->mTicksPerSecond < 0.0001f)
1268 : (
SLfloat)anim->mTicksPerSecond;
1269 SLfloat animDuration = (
SLfloat)anim->mDuration / animTicksPerSec;
1271 if (anim->mName.length > 0)
1272 animName = anim->mName.C_Str();
1275 logMessage(
LV_minimal,
"\nLoading animation %s\n", animName.c_str());
1276 logMessage(
LV_normal,
" Duration(seconds): %f \n", animDuration);
1277 logMessage(
LV_normal,
" Duration(ticks): %f \n", anim->mDuration);
1278 logMessage(
LV_normal,
" Ticks per second: %f \n", animTicksPerSec);
1279 logMessage(
LV_normal,
" Num channels: %d\n", anim->mNumChannels);
1282 if (!_skinnedMeshes.empty())
1283 assert(_skeleton !=
nullptr &&
"The skeleton wasn't imported correctly.");
1288 result = _skeleton->createAnimation(animManager, animName, animDuration);
1292 _animationNamesMap.push_back(result);
1295 SLbool isSkeletonAnim =
false;
1296 for (
SLuint i = 0; i < anim->mNumChannels; i++)
1298 aiNodeAnim* channel = anim->mChannels[i];
1301 SLstring nodeName = channel->mNodeName.C_Str();
1304 SLbool isJointNode = (affectedNode ==
nullptr);
1311 if (!isJointNode && isSkeletonAnim)
1315 if (_skeletonRoot && !affectedNode)
1317 isSkeletonAnim =
true;
1318 SLJoint* affectedJoint = _skeleton->getJoint(nodeName);
1319 if (affectedJoint ==
nullptr)
1322 id = affectedJoint->
id();
1352 affectedJoint->
om(prevOM);
1356 logMessage(
LV_normal,
"\n Channel %d %s", i, (isJointNode) ?
"(joint animation)\n" :
"\n");
1357 logMessage(
LV_normal,
" Affected node: %s\n", channel->mNodeName.C_Str());
1358 logMessage(
LV_detailed,
" Num position keys: %d\n", channel->mNumPositionKeys);
1359 logMessage(
LV_detailed,
" Num rotation keys: %d\n", channel->mNumRotationKeys);
1360 logMessage(
LV_detailed,
" Num scaling keys: %d\n", channel->mNumScalingKeys);
1366 if (affectedNode && !isSkeletonAnim)
1371 KeyframeMap keyframes;
1374 for (
SLuint iK = 0; iK < channel->mNumPositionKeys; iK++)
1376 SLfloat time = (
SLfloat)channel->mPositionKeys[iK].mTime / animTicksPerSec;
1377 keyframes[time] = SLImportKeyframe(&channel->mPositionKeys[iK],
nullptr,
nullptr);
1381 for (
SLuint iK = 0; iK < channel->mNumRotationKeys; iK++)
1383 SLfloat time = (
SLfloat)channel->mRotationKeys[iK].mTime / animTicksPerSec;
1385 if (keyframes.find(time) == keyframes.end())
1386 keyframes[time] = SLImportKeyframe(
nullptr, &channel->mRotationKeys[iK],
nullptr);
1390 assert(keyframes[time].rotation ==
nullptr &&
"There were two rotation keys assigned to the same timestamp.");
1391 keyframes[time].rotation = &channel->mRotationKeys[iK];
1396 for (
SLuint iK = 0; iK < channel->mNumScalingKeys; iK++)
1398 SLfloat time = (
SLfloat)channel->mScalingKeys[iK].mTime / animTicksPerSec;
1400 if (keyframes.find(time) == keyframes.end())
1401 keyframes[time] = SLImportKeyframe(
nullptr,
nullptr, &channel->mScalingKeys[iK]);
1405 assert(keyframes[time].scaling ==
nullptr &&
"There were two scaling keys assigned to the same timestamp.");
1406 keyframes[time].scaling = &channel->mScalingKeys[iK];
1410 logMessage(
LV_normal,
" Found %d distinct keyframe timestamp(s).\n", keyframes.size());
1412 for (
auto it : keyframes)
1415 kf->
translation(getTranslation(it.first, keyframes));
1416 kf->
rotation(getRotation(it.first, keyframes));
1417 kf->
scale(getScaling(it.first, keyframes));
1421 "\n Generating keyframe at time '%.2f'\n",
1424 " Translation: (%.2f, %.2f, %.2f) %s\n",
1428 (it.second.translation !=
nullptr) ?
"imported" :
"generated");
1430 " Rotation: (%.2f, %.2f, %.2f, %.2f) %s\n",
1435 (it.second.rotation !=
nullptr) ?
"imported" :
"generated");
1437 " Scale: (%.2f, %.2f, %.2f) %s\n",
1441 (it.second.scaling !=
nullptr) ?
"imported" :
"generated");
1459 SLbool SLAssimpImporter::aiNodeHasMesh(aiNode* node)
1461 if (node->mNumMeshes > 0)
return true;
1463 for (
SLuint i = 0; i < node->mNumChildren; i++)
1464 if (node->mChildren[i]->mNumMeshes > 0)
1465 return aiNodeHasMesh(node->mChildren[i]);
1484 SLstring pathFile = modelPath + aiTexFile;
1498 SL_LOG_DEBUG(
"**** WARNING ****: SLAssimpImporter: Texture file not found: %s from model %s",
1503 return texturePath +
"TexNotFound.png";
#define PROFILE_FUNCTION()
float SLfloat
analog to GLfloat
#define SL_LOG_DEBUG(...)
#define SL_LOG(...)
Some debugging and error handling macros.
unsigned int SLuint
analog to GLuint
#define SL_WARN_MSG(message)
unsigned char SLuchar
analog to GLuchar
bool SLbool
analog to GLbool
unsigned short SLushort
analog to GLushort
#define SL_EXIT_MSG(message)
signed char SLbyte
analog to GLbyte
string SLstring
Redefinition of standard types for platform independence.
Adapters that let Assimp read through SLProject's SLIOStream.
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()
Assimp file system handler backed by SLFileStorage.
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.
void setMatrix(const SLMat4 &A)
Set matrix by other 4x4 matrix.
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.