12 #ifdef SL_BUILD_WITH_ASSIMP
29 # include <assimp/Importer.hpp>
30 # include <assimp/scene.h>
31 # include <assimp/pbrmaterial.h>
35 struct SLImportKeyframe
38 : translation(nullptr),
44 SLImportKeyframe(aiVectorKey* trans, aiQuatKey* rot, aiVectorKey* scl)
51 aiVectorKey* translation;
55 typedef std::map<SLfloat, SLImportKeyframe> KeyframeMap;
66 KeyframeMap::const_iterator it = keyframes.find(time);
67 aiVector3D result(0, 0, 0);
71 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
73 aiVectorKey* transKey = it->second.translation;
77 result = transKey->mValue;
80 aiVectorKey* frontKey =
nullptr;
81 aiVectorKey* backKey =
nullptr;
84 KeyframeMap::const_reverse_iterator revIt(it);
87 for (; it != keyframes.end(); it++)
89 if (it->second.translation !=
nullptr)
91 backKey = it->second.translation;
97 for (; revIt != keyframes.rend(); revIt++)
99 if (revIt->second.translation !=
nullptr)
101 frontKey = revIt->second.translation;
106 if (frontKey && backKey)
108 SLfloat frontTime = revIt->first;
110 SLfloat t = (time - frontTime) / (backTime - frontTime);
112 result = frontKey->mValue + (t * (backKey->mValue - frontKey->mValue));
116 result = frontKey->mValue;
120 result = backKey->mValue;
124 return SLVec3f(result.x, result.y, result.z);
136 KeyframeMap::const_iterator it = keyframes.find(time);
137 aiVector3D result(1, 1, 1);
141 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
143 aiVectorKey* scaleKey = it->second.scaling;
147 result = scaleKey->mValue;
150 aiVectorKey* frontKey =
nullptr;
151 aiVectorKey* backKey =
nullptr;
154 KeyframeMap::const_reverse_iterator revIt(it);
157 for (; it != keyframes.end(); it++)
159 if (it->second.rotation !=
nullptr)
161 backKey = it->second.scaling;
167 for (; revIt != keyframes.rend(); revIt++)
169 if (revIt->second.rotation !=
nullptr)
171 frontKey = revIt->second.scaling;
176 if (frontKey && backKey)
178 SLfloat frontTime = revIt->first;
180 SLfloat t = (time - frontTime) / (backTime - frontTime);
182 result = frontKey->mValue + (t * (backKey->mValue - frontKey->mValue));
186 result = frontKey->mValue;
190 result = backKey->mValue;
194 return SLVec3f(result.x, result.y, result.z);
206 KeyframeMap::const_iterator it = keyframes.find(time);
207 aiQuaternion result(1, 0, 0, 0);
211 assert(it != keyframes.end() &&
"A KeyframeMap was passed in with an illegal timestamp.");
213 aiQuatKey* rotKey = it->second.rotation;
217 result = rotKey->mValue;
220 aiQuatKey* frontKey =
nullptr;
221 aiQuatKey* backKey =
nullptr;
224 KeyframeMap::const_reverse_iterator revIt(it);
227 for (; it != keyframes.end(); it++)
229 if (it->second.rotation !=
nullptr)
231 backKey = it->second.rotation;
237 for (; revIt != keyframes.rend(); revIt++)
239 if (revIt->second.rotation !=
nullptr)
241 frontKey = revIt->second.rotation;
246 if (frontKey && backKey)
248 SLfloat frontTime = revIt->first;
250 SLfloat t = (time - frontTime) / (backTime - frontTime);
252 aiQuaternion::Interpolate(result, frontKey->mValue, backKey->mValue, t);
256 result = frontKey->mValue;
260 result = backKey->mValue;
264 return SLQuat4f(result.x, result.y, result.z, result.w);
279 SLbool deleteTexImgAfterBuild,
283 SLbool forceCookTorranceRM,
284 SLProgressHandler* progressHandler,
296 SLstring msg =
"SLAssimpImporter: File not found: " + pathAndFile +
"\n";
306 ai.SetProgressHandler((Assimp::ProgressHandler*)progressHandler);
310 const aiScene* scene = ai.ReadFile(pathAndFile, (
SLuint)flags);
315 SLstring msg =
"Failed to load file: " + pathAndFile +
"\n" + ai.GetErrorString() +
"\n";
321 performInitialScan(scene);
324 loadSkeleton(aniMan,
nullptr, _skeletonRoot);
331 for (
SLint i = 0; i < (
SLint)scene->mNumMaterials; i++)
332 materials.push_back(loadMaterial(assetMgr,
334 scene->mMaterials[i],
340 deleteTexImgAfterBuild));
344 std::map<int, SLMesh*> meshMap;
345 for (
SLint i = 0; i < (
SLint)scene->mNumMeshes; i++)
347 SLMesh* mesh = loadMesh(assetMgr, scene->mMeshes[i]);
351 mesh->
mat(overrideMat);
353 mesh->
mat(materials[scene->mMeshes[i]->mMaterialIndex]);
354 _meshes.push_back(mesh);
358 SL_LOG(
"SLAsssimpImporter::load failed: %s\nin path: %s",
364 _sceneRoot = loadNodesRec(
nullptr, scene->mRootNode, meshMap, loadMeshesOnly);
367 vector<SLAnimation*> animations;
368 for (
SLint i = 0; i < (
SLint)scene->mNumAnimations; i++)
369 animations.push_back(loadAnimation(aniMan, scene->mAnimations[i]));
371 logMessage(
LV_minimal,
"\n---------------------------\n\n");
384 _jointOffsets.clear();
385 _skeletonRoot =
nullptr;
387 _skinnedMeshes.clear();
391 aiNode* SLAssimpImporter::getNodeByName(
const SLstring& name)
393 if (_nodeMap.find(name) != _nodeMap.end())
394 return _nodeMap[name];
402 if (_jointOffsets.find(name) != _jointOffsets.end())
403 return _jointOffsets[name];
409 void SLAssimpImporter::performInitialScan(
const aiScene* scene)
415 logMessage(
LV_detailed,
" Cameras: %d\n", scene->mNumCameras);
416 logMessage(
LV_detailed,
" Lights: %d\n", scene->mNumLights);
417 logMessage(
LV_detailed,
" Meshes: %d\n", scene->mNumMeshes);
418 logMessage(
LV_detailed,
" Materials: %d\n", scene->mNumMaterials);
419 logMessage(
LV_detailed,
" Textures: %d\n", scene->mNumTextures);
420 logMessage(
LV_detailed,
" Animations: %d\n", scene->mNumAnimations);
422 logMessage(
LV_detailed,
"---------------------------------------------\n");
424 findNodes(scene->mRootNode,
" ",
true);
426 logMessage(
LV_detailed,
"---------------------------------------------\n");
427 logMessage(
LV_detailed,
" Searching for skinned meshes and scanning joint names.\n");
434 void SLAssimpImporter::findNodes(aiNode* node,
SLstring padding,
SLbool lastChild)
436 SLstring name = node->mName.C_Str();
440 // rename duplicate node names
441 SLstring renamedString;
442 if (_nodeMap.find(name) != _nodeMap.end())
445 std::ostringstream ss;
446 SLstring lastMatch = name;
447 while (_nodeMap.find(lastMatch) != _nodeMap.end())
451 ss << name << "_" << std::setw( 2 ) << std::setfill( '0' ) << index;
452 lastMatch = ss.str();
457 ss << "(renamed from '" << name << "')";
458 renamedString = ss.str();
463 assert(_nodeMap.find(name) == _nodeMap.end() &&
"Duplicated node name found!");
464 _nodeMap[name] = node;
468 "%s |-[%s] (%d children, %d meshes)",
479 for (
SLuint i = 0; i < node->mNumChildren; i++)
481 findNodes(node->mChildren[i], padding, (i == node->mNumChildren - 1));
488 void SLAssimpImporter::findJoints(
const aiScene* scene)
490 for (
SLuint i = 0; i < scene->mNumMeshes; i++)
492 aiMesh* mesh = scene->mMeshes[i];
493 if (!mesh->HasBones())
497 " Mesh '%s' contains %d joints.\n",
501 for (
SLuint j = 0; j < mesh->mNumBones; j++)
503 SLstring name = mesh->mBones[j]->mName.C_Str();
504 std::map<SLstring, SLMat4f>::iterator it = _jointOffsets.find(name);
505 if (it != _jointOffsets.end())
510 memcpy(&offsetMat, &mesh->mBones[j]->mOffsetMatrix,
sizeof(
SLMat4f));
512 _jointOffsets[name] = offsetMat;
514 logMessage(
LV_detailed,
" Bone '%s' found.\n", name.c_str());
522 void SLAssimpImporter::findSkeletonRoot()
524 _skeletonRoot =
nullptr;
526 if (_jointOffsets.empty())
return;
528 vector<SLVaiNode> ancestorList(_jointOffsets.size());
529 SLint minDepth = INT_MAX;
532 logMessage(
LV_detailed,
"Building joint ancestor lists.\n");
534 auto it = _jointOffsets.begin();
535 for (; it != _jointOffsets.end(); it++, index++)
537 aiNode* node = getNodeByName(it->first);
538 SLVaiNode& list = ancestorList[index];
542 list.insert(list.begin(), node);
543 node = node->mParent;
550 " '%s' ancestor list: ",
562 " '%s' lies at a depth of %d\n",
566 minDepth = std::min(minDepth, (
SLint)list.size());
570 "Bone ancestor lists completed, min depth: %d\n",
574 "Searching ancestor lists for common ancestor.\n");
580 aiNode* lastMatch = ancestorList[0][i];
581 for (
SLuint j = 1; j < ancestorList.size(); j++)
583 if (ancestorList[j][i] != lastMatch)
586 lastMatch = ancestorList[j][i];
592 _skeletonRoot = lastMatch;
594 "Found matching ancestor '%s'.\n",
595 _skeletonRoot->mName.C_Str());
607 _skeletonRoot = ancestorList[0][1];
610 "Determined '%s' to be the skeleton's root node.\n",
611 _skeletonRoot->mName.C_Str());
621 SLstring name = node->mName.C_Str();
625 logMessage(
LV_normal,
"Loading skeleton skeleton.\n");
627 animManager.
skeletons().push_back(_skeleton);
630 joint = _skeleton->createJoint(name, _jointIndex++);
631 _skeleton->rootJoint(joint);
666 for (
SLuint i = 0; i < node->mNumChildren; i++)
667 loadSkeleton(animManager, joint, node->mChildren[i]);
682 SLbool forceCookTorranceRM,
683 SLbool deleteTexImgAfterBuild)
689 aiMat->Get(AI_MATKEY_NAME, matName);
691 if (name.empty()) name =
"Import Material";
697 for (
int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
699 aiTextureType aiTexType = (aiTextureType)tt;
701 if (aiMat->GetTextureCount(aiTexType) > 0)
704 aiTextureMapping mappingType = aiTextureMapping_UV;
707 aiMat->GetTexture(aiTexType,
720 case aiTextureType_DIFFUSE: slTexType =
TT_diffuse;
break;
721 case aiTextureType_NORMALS: slTexType =
TT_normal;
break;
722 case aiTextureType_SPECULAR: slTexType =
TT_specular;
break;
723 case aiTextureType_HEIGHT: slTexType =
TT_height;
break;
724 case aiTextureType_OPACITY: slTexType =
TT_diffuse;
break;
725 case aiTextureType_EMISSIVE: slTexType =
TT_emissive;
break;
726 case aiTextureType_LIGHTMAP:
729 aiString fileRoughnessMetallic;
730 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
731 &fileRoughnessMetallic);
732 SLstring occRghMtlTex = checkFilePath(modelPath,
734 fileRoughnessMetallic.data,
736 SLstring occlusionTex = checkFilePath(modelPath,
740 if (occRghMtlTex == occlusionTex)
753 case aiTextureType_AMBIENT_OCCLUSION:
756 aiString fileRoughnessMetallic;
757 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
758 &fileRoughnessMetallic);
759 SLstring occRghMtlTex = checkFilePath(modelPath,
761 fileRoughnessMetallic.data,
763 SLstring occlusionTex = checkFilePath(modelPath,
767 if (occRghMtlTex == occlusionTex)
773 case aiTextureType_UNKNOWN:
776 aiString fileMetallicRoughness;
777 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
778 &fileMetallicRoughness);
779 SLstring rghMtlTex = checkFilePath(modelPath,
781 fileMetallicRoughness.data,
783 SLstring unknownTex = checkFilePath(modelPath,
787 if (rghMtlTex == unknownTex)
790 aiString fileOcclusion;
791 aiMat->GetTexture(aiTextureType_LIGHTMAP,
794 SLstring occlusionTex = checkFilePath(modelPath,
798 if (rghMtlTex == occlusionTex)
810 SLstring texFile = checkFilePath(modelPath, texturePath, aiPath.data);
825 deleteTexImgAfterBuild);
832 aiColor3D ambient, diffuse, specular, emissive;
833 SLfloat shininess, refracti, reflectivity, opacity, roughness = -1, metalness = -1;
834 aiMat->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
835 aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
836 aiMat->Get(AI_MATKEY_COLOR_SPECULAR, specular);
837 aiMat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive);
838 aiMat->Get(AI_MATKEY_SHININESS, shininess);
839 aiMat->Get(AI_MATKEY_REFRACTI, refracti);
840 aiMat->Get(AI_MATKEY_REFLECTIVITY, reflectivity);
841 aiMat->Get(AI_MATKEY_OPACITY, opacity);
842 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metalness);
843 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, roughness);
847 if (specular.r > 0.5f &&
854 if (ambientFactor > 0.0f)
856 diffuse.g * ambientFactor,
857 diffuse.b * ambientFactor));
879 if (roughness == -1.0f)
882 if (metalness == -1.0f)
900 SLbool deleteTexImgAfterBuild)
907 for (
auto& i : allLoadedTex)
908 if (i->url() == textureFile)
922 if (deleteTexImgAfterBuild)
943 for (
unsigned int i = 0; i < mesh->mNumFaces; ++i)
945 if (mesh->mFaces[i].mNumIndices == 1) numPoints++;
946 if (mesh->mFaces[i].mNumIndices == 2) numLines++;
947 if (mesh->mFaces[i].mNumIndices == 3) numTriangles++;
948 if (mesh->mFaces[i].mNumIndices > 3) numPolygons++;
952 if ((numTriangles && (numLines || numPoints)) ||
953 (numLines && (numTriangles || numPoints)) ||
954 (numPoints && (numLines || numTriangles)))
962 if (numTriangles && numLines) numLines = 0;
963 if (numTriangles && numPoints) numPoints = 0;
964 if (numLines && numPoints) numPoints = 0;
969 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh contains polygons: %s",
970 mesh->mName.C_Str());
975 if (mesh->mNumVertices == 0)
977 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has no vertices: %s",
978 mesh->mName.C_Str());
983 if (numTriangles == 0 && numLines == 0 && numPoints == 0)
985 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has has no triangles nor lines nor points: %s",
986 mesh->mName.C_Str());
993 SLMesh* m =
new SLMesh(am, name.empty() ?
"Imported Mesh" : name);
1002 m->
P.resize(mesh->mNumVertices);
1005 if (mesh->HasNormals() && numTriangles)
1008 m->
N.resize(m->
P.size());
1012 if (mesh->HasTextureCoords(0) && numTriangles)
1015 m->
UV[0].resize(m->
P.size());
1020 if (mesh->HasTextureCoords(1) && numTriangles)
1023 m->
UV[1].resize(m->
P.size());
1027 for (
SLuint i = 0; i < m->
P.size(); ++i)
1029 m->
P[i].set(mesh->mVertices[i].x,
1030 mesh->mVertices[i].y,
1031 mesh->mVertices[i].z);
1033 m->
N[i].set(mesh->mNormals[i].x,
1034 mesh->mNormals[i].y,
1035 mesh->mNormals[i].z);
1036 if (!m->
UV[0].empty())
1037 m->
UV[0][i].set(mesh->mTextureCoords[0][i].x,
1038 mesh->mTextureCoords[0][i].y);
1039 if (!m->
UV[1].empty())
1040 m->
UV[1][i].set(mesh->mTextureCoords[1][i].x,
1041 mesh->mTextureCoords[1][i].y);
1046 if (m->
P.size() < 65536)
1051 m->
I16.resize((
static_cast<size_t>(numTriangles * 3)));
1052 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1054 if (mesh->mFaces[i].mNumIndices == 3)
1056 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1057 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1058 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[2];
1064 m->
I16.resize((
size_t)numLines * 2);
1065 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1067 if (mesh->mFaces[i].mNumIndices == 2)
1069 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1070 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1076 m->
I16.resize(numPoints);
1077 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1079 if (mesh->mFaces[i].mNumIndices == 1)
1080 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1085 for (
auto i : m->
I16)
1086 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1093 m->
I32.resize((
size_t)numTriangles * 3);
1094 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1096 if (mesh->mFaces[i].mNumIndices == 3)
1098 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1099 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1100 m->
I32[j++] = mesh->mFaces[i].mIndices[2];
1106 m->
I32.resize((
size_t)numLines * 2);
1107 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1109 if (mesh->mFaces[i].mNumIndices == 2)
1111 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1112 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1118 m->
I32.resize((
size_t)numPoints * 1);
1119 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1121 if (mesh->mFaces[i].mNumIndices == 1)
1122 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1127 for (
auto i : m->
I32)
1128 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1131 if (!mesh->HasNormals() && numTriangles)
1135 if (mesh->HasBones())
1137 _skinnedMeshes.push_back(m);
1140 m->
Ji.resize(m->
P.size());
1141 m->
Jw.resize(m->
P.size());
1143 for (
SLuint i = 0; i < mesh->mNumBones; i++)
1145 aiBone* joint = mesh->mBones[i];
1146 SLJoint* slJoint = _skeleton->getJoint(joint->mName.C_Str());
1151 for (
SLuint nW = 0; nW < joint->mNumWeights; nW++)
1154 SLuint vertId = joint->mWeights[nW].mVertexId;
1155 SLfloat weight = joint->mWeights[nW].mWeight;
1158 m->
Jw[vertId].push_back(weight);
1165 mesh->mVertices[vertId].y,
1166 mesh->mVertices[vertId].z));
1171 SL_LOG(
"Failed to load joint of skeleton in SLAssimpImporter::loadMesh: %s",
1172 joint->mName.C_Str());
1184 SLNode* SLAssimpImporter::loadNodesRec(
SLNode* curNode,
1193 curNode =
new SLNode(node->mName.data);
1196 aiMatrix4x4* M = &node->mTransformation;
1199 SLMat4f SLM(M->a1, M->a2, M->a3, M->a4,
1200 M->b1, M->b2, M->b3, M->b4,
1201 M->c1, M->c2, M->c3, M->c4,
1202 M->d1, M->d2, M->d3, M->d4);
1209 if (node->mNumMeshes > 1)
1211 for (
SLuint i = 0; i < node->mNumMeshes; ++i)
1214 if (meshes.count((
SLint)node->mMeshes[i]))
1216 SLstring nodeMeshName = node->mName.data;
1217 nodeMeshName +=
"-";
1218 nodeMeshName += meshes[(
SLint)node->mMeshes[i]]->name();
1225 else if (node->mNumMeshes == 1)
1228 if (meshes.count((
SLint)node->mMeshes[0]))
1233 for (
SLuint i = 0; i < node->mNumChildren; i++)
1236 if (node->mChildren[i] == _skeletonRoot)
1240 if (!loadMeshesOnly || aiNodeHasMesh(node->mChildren[i]))
1242 SLNode* child =
new SLNode(node->mChildren[i]->mName.data);
1244 loadNodesRec(child, node->mChildren[i], meshes);
1259 SLfloat animTicksPerSec = (anim->mTicksPerSecond < 0.0001f)
1261 : (
SLfloat)anim->mTicksPerSecond;
1262 SLfloat animDuration = (
SLfloat)anim->mDuration / animTicksPerSec;
1264 if (anim->mName.length > 0)
1265 animName = anim->mName.C_Str();
1268 logMessage(
LV_minimal,
"\nLoading animation %s\n", animName.c_str());
1269 logMessage(
LV_normal,
" Duration(seconds): %f \n", animDuration);
1270 logMessage(
LV_normal,
" Duration(ticks): %f \n", anim->mDuration);
1271 logMessage(
LV_normal,
" Ticks per second: %f \n", animTicksPerSec);
1272 logMessage(
LV_normal,
" Num channels: %d\n", anim->mNumChannels);
1275 if (!_skinnedMeshes.empty())
1276 assert(_skeleton !=
nullptr &&
"The skeleton wasn't imported correctly.");
1281 result = _skeleton->createAnimation(animManager, animName, animDuration);
1285 _animationNamesMap.push_back(result);
1288 SLbool isSkeletonAnim =
false;
1289 for (
SLuint i = 0; i < anim->mNumChannels; i++)
1291 aiNodeAnim* channel = anim->mChannels[i];
1294 SLstring nodeName = channel->mNodeName.C_Str();
1297 SLbool isJointNode = (affectedNode ==
nullptr);
1304 if (!isJointNode && isSkeletonAnim)
1308 if (_skeletonRoot && !affectedNode)
1310 isSkeletonAnim =
true;
1311 SLJoint* affectedJoint = _skeleton->getJoint(nodeName);
1312 if (affectedJoint ==
nullptr)
1315 id = affectedJoint->
id();
1345 affectedJoint->
om(prevOM);
1349 logMessage(
LV_normal,
"\n Channel %d %s", i, (isJointNode) ?
"(joint animation)\n" :
"\n");
1350 logMessage(
LV_normal,
" Affected node: %s\n", channel->mNodeName.C_Str());
1351 logMessage(
LV_detailed,
" Num position keys: %d\n", channel->mNumPositionKeys);
1352 logMessage(
LV_detailed,
" Num rotation keys: %d\n", channel->mNumRotationKeys);
1353 logMessage(
LV_detailed,
" Num scaling keys: %d\n", channel->mNumScalingKeys);
1359 if (affectedNode && !isSkeletonAnim)
1364 KeyframeMap keyframes;
1367 for (
SLuint iK = 0; iK < channel->mNumPositionKeys; iK++)
1369 SLfloat time = (
SLfloat)channel->mPositionKeys[iK].mTime / animTicksPerSec;
1370 keyframes[time] = SLImportKeyframe(&channel->mPositionKeys[iK],
nullptr,
nullptr);
1374 for (
SLuint iK = 0; iK < channel->mNumRotationKeys; iK++)
1376 SLfloat time = (
SLfloat)channel->mRotationKeys[iK].mTime / animTicksPerSec;
1378 if (keyframes.find(time) == keyframes.end())
1379 keyframes[time] = SLImportKeyframe(
nullptr, &channel->mRotationKeys[iK],
nullptr);
1383 assert(keyframes[time].rotation ==
nullptr &&
"There were two rotation keys assigned to the same timestamp.");
1384 keyframes[time].rotation = &channel->mRotationKeys[iK];
1389 for (
SLuint iK = 0; iK < channel->mNumScalingKeys; iK++)
1391 SLfloat time = (
SLfloat)channel->mScalingKeys[iK].mTime / animTicksPerSec;
1393 if (keyframes.find(time) == keyframes.end())
1394 keyframes[time] = SLImportKeyframe(
nullptr,
nullptr, &channel->mScalingKeys[iK]);
1398 assert(keyframes[time].scaling ==
nullptr &&
"There were two scaling keys assigned to the same timestamp.");
1399 keyframes[time].scaling = &channel->mScalingKeys[iK];
1403 logMessage(
LV_normal,
" Found %d distinct keyframe timestamp(s).\n", keyframes.size());
1405 for (
auto it : keyframes)
1408 kf->
translation(getTranslation(it.first, keyframes));
1409 kf->
rotation(getRotation(it.first, keyframes));
1410 kf->
scale(getScaling(it.first, keyframes));
1414 "\n Generating keyframe at time '%.2f'\n",
1417 " Translation: (%.2f, %.2f, %.2f) %s\n",
1421 (it.second.translation !=
nullptr) ?
"imported" :
"generated");
1423 " Rotation: (%.2f, %.2f, %.2f, %.2f) %s\n",
1428 (it.second.rotation !=
nullptr) ?
"imported" :
"generated");
1430 " Scale: (%.2f, %.2f, %.2f) %s\n",
1434 (it.second.scaling !=
nullptr) ?
"imported" :
"generated");
1452 SLbool SLAssimpImporter::aiNodeHasMesh(aiNode* node)
1454 if (node->mNumMeshes > 0)
return true;
1456 for (
SLuint i = 0; i < node->mNumChildren; i++)
1457 if (node->mChildren[i]->mNumMeshes > 0)
1458 return aiNodeHasMesh(node->mChildren[i]);
1477 SLstring pathFile = modelPath + aiTexFile;
1491 SL_LOG_DEBUG(
"**** WARNING ****: SLAssimpImporter: Texture file not found: %s from model %s",
1496 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.