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())
508 memcpy(&offsetMat, &mesh->mBones[j]->mOffsetMatrix,
sizeof(
SLMat4f));
510 _jointOffsets[name] = offsetMat;
512 logMessage(
LV_detailed,
" Bone '%s' found.\n", name.c_str());
520 void SLAssimpImporter::findSkeletonRoot()
522 _skeletonRoot =
nullptr;
524 if (_jointOffsets.empty())
return;
526 vector<SLVaiNode> ancestorList(_jointOffsets.size());
527 SLint minDepth = INT_MAX;
530 logMessage(
LV_detailed,
"Building joint ancestor lists.\n");
532 auto it = _jointOffsets.begin();
533 for (; it != _jointOffsets.end(); it++, index++)
535 aiNode* node = getNodeByName(it->first);
536 SLVaiNode& list = ancestorList[index];
540 list.insert(list.begin(), node);
541 node = node->mParent;
548 " '%s' ancestor list: ",
560 " '%s' lies at a depth of %d\n",
564 minDepth = std::min(minDepth, (
SLint)list.size());
568 "Bone ancestor lists completed, min depth: %d\n",
572 "Searching ancestor lists for common ancestor.\n");
578 aiNode* lastMatch = ancestorList[0][i];
579 for (
SLuint j = 1; j < ancestorList.size(); j++)
581 if (ancestorList[j][i] != lastMatch)
584 lastMatch = ancestorList[j][i];
590 _skeletonRoot = lastMatch;
592 "Found matching ancestor '%s'.\n",
593 _skeletonRoot->mName.C_Str());
605 _skeletonRoot = ancestorList[0][1];
608 "Determined '%s' to be the skeleton's root node.\n",
609 _skeletonRoot->mName.C_Str());
619 SLstring name = node->mName.C_Str();
623 logMessage(
LV_normal,
"Loading skeleton skeleton.\n");
625 animManager.
skeletons().push_back(_skeleton);
628 joint = _skeleton->createJoint(name, _jointIndex++);
629 _skeleton->rootJoint(joint);
664 for (
SLuint i = 0; i < node->mNumChildren; i++)
665 loadSkeleton(animManager, joint, node->mChildren[i]);
680 SLbool forceCookTorranceRM,
681 SLbool deleteTexImgAfterBuild)
687 aiMat->Get(AI_MATKEY_NAME, matName);
689 if (name.empty()) name =
"Import Material";
695 for (
int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
697 aiTextureType aiTexType = (aiTextureType)tt;
699 if (aiMat->GetTextureCount(aiTexType) > 0)
702 aiTextureMapping mappingType = aiTextureMapping_UV;
705 aiMat->GetTexture(aiTexType,
718 case aiTextureType_DIFFUSE: slTexType =
TT_diffuse;
break;
719 case aiTextureType_NORMALS: slTexType =
TT_normal;
break;
720 case aiTextureType_SPECULAR: slTexType =
TT_specular;
break;
721 case aiTextureType_HEIGHT: slTexType =
TT_height;
break;
722 case aiTextureType_OPACITY: slTexType =
TT_diffuse;
break;
723 case aiTextureType_EMISSIVE: slTexType =
TT_emissive;
break;
724 case aiTextureType_LIGHTMAP:
727 aiString fileRoughnessMetallic;
728 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
729 &fileRoughnessMetallic);
730 SLstring occRghMtlTex = checkFilePath(modelPath,
732 fileRoughnessMetallic.data,
734 SLstring occlusionTex = checkFilePath(modelPath,
738 if (occRghMtlTex == occlusionTex)
751 case aiTextureType_AMBIENT_OCCLUSION:
754 aiString fileRoughnessMetallic;
755 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
756 &fileRoughnessMetallic);
757 SLstring occRghMtlTex = checkFilePath(modelPath,
759 fileRoughnessMetallic.data,
761 SLstring occlusionTex = checkFilePath(modelPath,
765 if (occRghMtlTex == occlusionTex)
771 case aiTextureType_UNKNOWN:
774 aiString fileMetallicRoughness;
775 aiMat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE,
776 &fileMetallicRoughness);
777 SLstring rghMtlTex = checkFilePath(modelPath,
779 fileMetallicRoughness.data,
781 SLstring unknownTex = checkFilePath(modelPath,
785 if (rghMtlTex == unknownTex)
788 aiString fileOcclusion;
789 aiMat->GetTexture(aiTextureType_LIGHTMAP,
792 SLstring occlusionTex = checkFilePath(modelPath,
796 if (rghMtlTex == occlusionTex)
808 SLstring texFile = checkFilePath(modelPath, texturePath, aiPath.data);
823 deleteTexImgAfterBuild);
830 aiColor3D ambient, diffuse, specular, emissive;
831 SLfloat shininess, refracti, reflectivity, transparencyFactor, opacity, roughness = -1, metalness = -1;
832 aiMat->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
833 aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
834 aiMat->Get(AI_MATKEY_COLOR_SPECULAR, specular);
835 aiMat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive);
836 aiMat->Get(AI_MATKEY_SHININESS, shininess);
837 aiMat->Get(AI_MATKEY_REFRACTI, refracti);
838 aiMat->Get(AI_MATKEY_REFLECTIVITY, reflectivity);
839 aiMat->Get(AI_MATKEY_OPACITY, opacity);
840 aiMat->Get(AI_MATKEY_TRANSPARENCYFACTOR, transparencyFactor);
841 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metalness);
842 aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, roughness);
846 if (specular.r > 0.5f &&
853 if (ambientFactor > 0.0f)
855 diffuse.g * ambientFactor,
856 diffuse.b * ambientFactor));
878 if (roughness == -1.0f)
881 if (metalness == -1.0f)
899 SLbool deleteTexImgAfterBuild)
906 for (
auto& i : allLoadedTex)
907 if (i->url() == textureFile)
921 if (deleteTexImgAfterBuild)
942 for (
unsigned int i = 0; i < mesh->mNumFaces; ++i)
944 if (mesh->mFaces[i].mNumIndices == 1) numPoints++;
945 if (mesh->mFaces[i].mNumIndices == 2) numLines++;
946 if (mesh->mFaces[i].mNumIndices == 3) numTriangles++;
947 if (mesh->mFaces[i].mNumIndices > 3) numPolygons++;
951 if ((numTriangles && (numLines || numPoints)) ||
952 (numLines && (numTriangles || numPoints)) ||
953 (numPoints && (numLines || numTriangles)))
961 if (numTriangles && numLines) numLines = 0;
962 if (numTriangles && numPoints) numPoints = 0;
963 if (numLines && numPoints) numPoints = 0;
968 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh contains polygons: %s",
969 mesh->mName.C_Str());
974 if (mesh->mNumVertices == 0)
976 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has no vertices: %s",
977 mesh->mName.C_Str());
982 if (numTriangles == 0 && numLines == 0 && numPoints == 0)
984 SL_LOG(
"SLAssimpImporter::loadMesh: Mesh has has no triangles nor lines nor points: %s",
985 mesh->mName.C_Str());
992 SLMesh* m =
new SLMesh(am, name.empty() ?
"Imported Mesh" : name);
1001 m->
P.resize(mesh->mNumVertices);
1004 if (mesh->HasNormals() && numTriangles)
1007 m->
N.resize(m->
P.size());
1011 if (mesh->HasTextureCoords(0) && numTriangles)
1014 m->
UV[0].resize(m->
P.size());
1019 if (mesh->HasTextureCoords(1) && numTriangles)
1022 m->
UV[1].resize(m->
P.size());
1026 for (
SLuint i = 0; i < m->
P.size(); ++i)
1028 m->
P[i].set(mesh->mVertices[i].x,
1029 mesh->mVertices[i].y,
1030 mesh->mVertices[i].z);
1032 m->
N[i].set(mesh->mNormals[i].x,
1033 mesh->mNormals[i].y,
1034 mesh->mNormals[i].z);
1035 if (!m->
UV[0].empty())
1036 m->
UV[0][i].set(mesh->mTextureCoords[0][i].x,
1037 mesh->mTextureCoords[0][i].y);
1038 if (!m->
UV[1].empty())
1039 m->
UV[1][i].set(mesh->mTextureCoords[1][i].x,
1040 mesh->mTextureCoords[1][i].y);
1045 if (m->
P.size() < 65536)
1050 m->
I16.resize((
static_cast<size_t>(numTriangles * 3)));
1051 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1053 if (mesh->mFaces[i].mNumIndices == 3)
1055 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1056 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1057 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[2];
1063 m->
I16.resize((
size_t)numLines * 2);
1064 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1066 if (mesh->mFaces[i].mNumIndices == 2)
1068 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1069 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[1];
1075 m->
I16.resize(numPoints);
1076 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1078 if (mesh->mFaces[i].mNumIndices == 1)
1079 m->
I16[j++] = (
SLushort)mesh->mFaces[i].mIndices[0];
1084 for (
auto i : m->
I16)
1085 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1092 m->
I32.resize((
size_t)numTriangles * 3);
1093 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1095 if (mesh->mFaces[i].mNumIndices == 3)
1097 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1098 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1099 m->
I32[j++] = mesh->mFaces[i].mIndices[2];
1105 m->
I32.resize((
size_t)numLines * 2);
1106 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1108 if (mesh->mFaces[i].mNumIndices == 2)
1110 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1111 m->
I32[j++] = mesh->mFaces[i].mIndices[1];
1117 m->
I32.resize((
size_t)numPoints * 1);
1118 for (
SLuint i = 0; i < mesh->mNumFaces; ++i)
1120 if (mesh->mFaces[i].mNumIndices == 1)
1121 m->
I32[j++] = mesh->mFaces[i].mIndices[0];
1126 for (
auto i : m->
I32)
1127 assert(i < m->P.size() &&
"SLAssimpImporter::loadMesh: Invalid Index");
1130 if (!mesh->HasNormals() && numTriangles)
1134 if (mesh->HasBones())
1136 _skinnedMeshes.push_back(m);
1139 m->
Ji.resize(m->
P.size());
1140 m->
Jw.resize(m->
P.size());
1142 for (
SLuint i = 0; i < mesh->mNumBones; i++)
1144 aiBone* joint = mesh->mBones[i];
1145 SLJoint* slJoint = _skeleton->getJoint(joint->mName.C_Str());
1150 for (
SLuint nW = 0; nW < joint->mNumWeights; nW++)
1153 SLuint vertId = joint->mWeights[nW].mVertexId;
1154 SLfloat weight = joint->mWeights[nW].mWeight;
1157 m->
Jw[vertId].push_back(weight);
1164 mesh->mVertices[vertId].y,
1165 mesh->mVertices[vertId].z));
1170 SL_LOG(
"Failed to load joint of skeleton in SLAssimpImporter::loadMesh: %s",
1171 joint->mName.C_Str());
1183 SLNode* SLAssimpImporter::loadNodesRec(
SLNode* curNode,
1192 curNode =
new SLNode(node->mName.data);
1195 aiMatrix4x4* M = &node->mTransformation;
1198 SLMat4f SLM(M->a1, M->a2, M->a3, M->a4,
1199 M->b1, M->b2, M->b3, M->b4,
1200 M->c1, M->c2, M->c3, M->c4,
1201 M->d1, M->d2, M->d3, M->d4);
1208 if (node->mNumMeshes > 1)
1210 for (
SLuint i = 0; i < node->mNumMeshes; ++i)
1213 if (meshes.count((
SLint)node->mMeshes[i]))
1215 SLstring nodeMeshName = node->mName.data;
1216 nodeMeshName +=
"-";
1217 nodeMeshName += meshes[(
SLint)node->mMeshes[i]]->name();
1224 else if (node->mNumMeshes == 1)
1227 if (meshes.count((
SLint)node->mMeshes[0]))
1232 for (
SLuint i = 0; i < node->mNumChildren; i++)
1235 if (node->mChildren[i] == _skeletonRoot)
1239 if (!loadMeshesOnly || aiNodeHasMesh(node->mChildren[i]))
1241 SLNode* child =
new SLNode(node->mChildren[i]->mName.data);
1243 loadNodesRec(child, node->mChildren[i], meshes);
1258 SLfloat animTicksPerSec = (anim->mTicksPerSecond < 0.0001f)
1260 : (
SLfloat)anim->mTicksPerSecond;
1261 SLfloat animDuration = (
SLfloat)anim->mDuration / animTicksPerSec;
1263 if (anim->mName.length > 0)
1264 animName = anim->mName.C_Str();
1267 logMessage(
LV_minimal,
"\nLoading animation %s\n", animName.c_str());
1268 logMessage(
LV_normal,
" Duration(seconds): %f \n", animDuration);
1269 logMessage(
LV_normal,
" Duration(ticks): %f \n", anim->mDuration);
1270 logMessage(
LV_normal,
" Ticks per second: %f \n", animTicksPerSec);
1271 logMessage(
LV_normal,
" Num channels: %d\n", anim->mNumChannels);
1274 if (!_skinnedMeshes.empty())
1275 assert(_skeleton !=
nullptr &&
"The skeleton wasn't imported correctly.");
1280 result = _skeleton->createAnimation(animManager, animName, animDuration);
1284 _animationNamesMap.push_back(result);
1287 SLbool isSkeletonAnim =
false;
1288 for (
SLuint i = 0; i < anim->mNumChannels; i++)
1290 aiNodeAnim* channel = anim->mChannels[i];
1293 SLstring nodeName = channel->mNodeName.C_Str();
1296 SLbool isJointNode = (affectedNode ==
nullptr);
1303 if (!isJointNode && isSkeletonAnim)
1307 if (_skeletonRoot && !affectedNode)
1309 isSkeletonAnim =
true;
1310 SLJoint* affectedJoint = _skeleton->getJoint(nodeName);
1311 if (affectedJoint ==
nullptr)
1314 id = affectedJoint->
id();
1344 affectedJoint->
om(prevOM);
1348 logMessage(
LV_normal,
"\n Channel %d %s", i, (isJointNode) ?
"(joint animation)\n" :
"\n");
1349 logMessage(
LV_normal,
" Affected node: %s\n", channel->mNodeName.C_Str());
1350 logMessage(
LV_detailed,
" Num position keys: %d\n", channel->mNumPositionKeys);
1351 logMessage(
LV_detailed,
" Num rotation keys: %d\n", channel->mNumRotationKeys);
1352 logMessage(
LV_detailed,
" Num scaling keys: %d\n", channel->mNumScalingKeys);
1358 if (affectedNode && !isSkeletonAnim)
1363 KeyframeMap keyframes;
1366 for (
SLuint iK = 0; iK < channel->mNumPositionKeys; iK++)
1368 SLfloat time = (
SLfloat)channel->mPositionKeys[iK].mTime / animTicksPerSec;
1369 keyframes[time] = SLImportKeyframe(&channel->mPositionKeys[iK],
nullptr,
nullptr);
1373 for (
SLuint iK = 0; iK < channel->mNumRotationKeys; iK++)
1375 SLfloat time = (
SLfloat)channel->mRotationKeys[iK].mTime / animTicksPerSec;
1377 if (keyframes.find(time) == keyframes.end())
1378 keyframes[time] = SLImportKeyframe(
nullptr, &channel->mRotationKeys[iK],
nullptr);
1382 assert(keyframes[time].rotation ==
nullptr &&
"There were two rotation keys assigned to the same timestamp.");
1383 keyframes[time].rotation = &channel->mRotationKeys[iK];
1388 for (
SLuint iK = 0; iK < channel->mNumScalingKeys; iK++)
1390 SLfloat time = (
SLfloat)channel->mScalingKeys[iK].mTime / animTicksPerSec;
1392 if (keyframes.find(time) == keyframes.end())
1393 keyframes[time] = SLImportKeyframe(
nullptr,
nullptr, &channel->mScalingKeys[iK]);
1397 assert(keyframes[time].scaling ==
nullptr &&
"There were two scaling keys assigned to the same timestamp.");
1398 keyframes[time].scaling = &channel->mScalingKeys[iK];
1402 logMessage(
LV_normal,
" Found %d distinct keyframe timestamp(s).\n", keyframes.size());
1404 for (
auto it : keyframes)
1407 kf->
translation(getTranslation(it.first, keyframes));
1408 kf->
rotation(getRotation(it.first, keyframes));
1409 kf->
scale(getScaling(it.first, keyframes));
1413 "\n Generating keyframe at time '%.2f'\n",
1416 " Translation: (%.2f, %.2f, %.2f) %s\n",
1420 (it.second.translation !=
nullptr) ?
"imported" :
"generated");
1422 " Rotation: (%.2f, %.2f, %.2f, %.2f) %s\n",
1427 (it.second.rotation !=
nullptr) ?
"imported" :
"generated");
1429 " Scale: (%.2f, %.2f, %.2f) %s\n",
1433 (it.second.scaling !=
nullptr) ?
"imported" :
"generated");
1451 SLbool SLAssimpImporter::aiNodeHasMesh(aiNode* node)
1453 if (node->mNumMeshes > 0)
return true;
1455 for (
SLuint i = 0; i < node->mNumChildren; i++)
1456 if (node->mChildren[i]->mNumMeshes > 0)
1457 return aiNodeHasMesh(node->mChildren[i]);
1476 SLstring pathFile = modelPath + aiTexFile;
1490 SL_LOG_DEBUG(
"**** WARNING ****: SLAssimpImporter: Texture file not found: %s from model %s",
1495 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.