42 #include <assimp/postprocess.h>
44 using std::ostringstream;
45 using std::stringstream;
53 : joint_vertex_xform(joint_vertex_xform), weight(weight)
75 _importer.FreeScene();
85 _importer.GetExtensionList(aexts);
88 char *sub = strtok(aexts.data,
";");
89 while (sub !=
nullptr) {
91 sub = strtok(
nullptr,
";");
104 _filename = filename;
106 unsigned int flags = aiProcess_Triangulate | aiProcess_GenUVCoords;
108 if (assimp_calc_tangent_space) {
109 flags |= aiProcess_CalcTangentSpace;
111 if (assimp_join_identical_vertices) {
112 flags |= aiProcess_JoinIdenticalVertices;
114 if (assimp_improve_cache_locality) {
115 flags |= aiProcess_ImproveCacheLocality;
117 if (assimp_remove_redundant_materials) {
118 flags |= aiProcess_RemoveRedundantMaterials;
120 if (assimp_fix_infacing_normals) {
121 flags |= aiProcess_FixInfacingNormals;
123 if (assimp_optimize_meshes) {
124 flags |= aiProcess_OptimizeMeshes;
126 if (assimp_optimize_graph) {
127 flags |= aiProcess_OptimizeGraph;
129 if (assimp_flip_winding_order) {
130 flags |= aiProcess_FlipWindingOrder;
132 if (assimp_gen_normals) {
133 if (assimp_smooth_normal_angle == 0.0) {
134 flags |= aiProcess_GenNormals;
137 flags |= aiProcess_GenSmoothNormals;
138 _importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,
139 assimp_smooth_normal_angle);
143 _scene = _importer.ReadFile(_filename.c_str(), flags);
144 if (_scene ==
nullptr) {
159 nassertv(_scene !=
nullptr);
168 _textures =
new PT(
Texture)[_scene->mNumTextures];
169 for (
size_t i = 0; i < _scene->mNumTextures; ++i) {
174 _mat_states =
new CPT(
RenderState)[_scene->mNumMaterials];
175 for (
size_t i = 0; i < _scene->mNumMaterials; ++i) {
180 _geoms =
new PT(
Geom)[_scene->mNumMeshes];
181 _geom_matindices =
new unsigned int[_scene->mNumMeshes];
182 for (
size_t i = 0; i < _scene->mNumMeshes; ++i) {
187 if (_scene->mRootNode !=
nullptr) {
188 load_node(*_scene->mRootNode, _root);
192 for (
size_t i = 0; i < _scene->mNumLights; ++i) {
193 load_light(*_scene->mLights[i]);
197 delete[] _mat_states;
199 delete[] _geom_matindices;
205 const aiNode *AssimpLoader::
206 find_node(
const aiNode &root,
const aiString &name) {
209 if (root.mName == name) {
212 for (
size_t i = 0; i < root.mNumChildren; ++i) {
213 node = find_node(*root.mChildren[i], name);
227 load_texture(
size_t index) {
228 const aiTexture &tex = *_scene->mTextures[index];
232 if (tex.mHeight == 0) {
235 <<
"Reading embedded compressed texture with format " << tex.achFormatHint <<
" and size " << tex.mWidth <<
"\n";
237 str.
write((
char*) tex.pcData, tex.mWidth);
239 if (strncmp(tex.achFormatHint,
"dds", 3) == 0) {
248 if (strncmp(tex.achFormatHint,
"jp\0", 3) == 0) {
254 if (img.
read(str,
"", ftype)) {
262 <<
"Reading embedded raw texture with size " << tex.mWidth <<
"x" << tex.mHeight <<
"\n";
264 ptex->setup_2d_texture(tex.mWidth, tex.mHeight, Texture::T_unsigned_byte, Texture::F_rgba);
265 PTA_uchar data = ptex->modify_ram_image();
268 for (
size_t i = 0; i < tex.mWidth * tex.mHeight; ++i) {
269 const aiTexel &texel = tex.pcData[i];
280 _textures[index] = ptex;
288 load_texture_stage(
const aiMaterial &mat,
const aiTextureType &ttype, CPT(
TextureAttrib) &tattr) {
290 aiTextureMapping mapping;
291 unsigned int uvindex;
294 aiTextureMapMode mapmode;
296 for (
size_t i = 0; i < mat.GetTextureCount(ttype); ++i) {
297 mat.GetTexture(ttype, i, &path, &mapping,
nullptr, &blend, &op, &mapmode);
299 if (AI_SUCCESS != mat.Get(AI_MATKEY_UVWSRC(ttype, i), uvindex)) {
310 stage->set_texcoord_name(InternalName::get_texcoord_name(str.str()));
316 if (path.data[0] ==
'*') {
317 long num = strtol(path.data + 1,
nullptr, 10);
318 ptex = _textures[num];
320 }
else if (path.length > 0) {
350 if (ptex !=
nullptr) {
351 tattr = DCAST(
TextureAttrib, tattr->add_on_stage(stage, ptex));
360 load_material(
size_t index) {
361 const aiMaterial &mat = *_scene->mMaterials[index];
363 CPT(
RenderState) state = RenderState::make_empty();
375 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_DIFFUSE, col)) {
379 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_SPECULAR, col)) {
380 if (AI_SUCCESS == mat.Get(AI_MATKEY_SHININESS_STRENGTH, fval)) {
381 pmat->set_specular(LColor(col.r * fval, col.g * fval, col.b * fval, 1));
383 pmat->set_specular(LColor(col.r, col.g, col.b, 1));
387 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_AMBIENT, col)) {
388 pmat->set_specular(LColor(col.r, col.g, col.b, 1));
391 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_EMISSIVE, col)) {
392 pmat->set_emission(LColor(col.r, col.g, col.b, 1));
395 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_TRANSPARENT, col)) {
398 if (AI_SUCCESS == mat.Get(AI_MATKEY_SHININESS, fval)) {
399 pmat->set_shininess(fval);
403 state = state->add_attrib(MaterialAttrib::make(pmat));
407 if (AI_SUCCESS == mat.Get(AI_MATKEY_ENABLE_WIREFRAME, ival)) {
409 state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe));
411 state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled));
417 if (AI_SUCCESS == mat.Get(AI_MATKEY_TWOSIDED, ival)) {
419 state = state->add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
421 state = state->add_attrib(CullFaceAttrib::make_default());
427 load_texture_stage(mat, aiTextureType_DIFFUSE, tattr);
428 load_texture_stage(mat, aiTextureType_LIGHTMAP, tattr);
430 state = state->add_attrib(tattr);
433 _mat_states[index] = state;
441 const aiMatrix4x4 &t = node.mTransformation;
442 LMatrix4 mat(t.a1, t.b1, t.c1, t.d1,
443 t.a2, t.b2, t.c2, t.d2,
444 t.a3, t.b3, t.c3, t.d3,
445 t.a4, t.b4, t.c4, t.d4);
449 <<
"Creating joint for: " << node.mName.C_Str() <<
"\n";
451 for (
size_t i = 0; i < node.mNumChildren; ++i) {
452 if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
453 create_joint(character, bundle, joint, *node.mChildren[i]);
462 create_anim_channel(
const aiAnimation &anim,
AnimBundle *bundle,
AnimGroup *parent,
const aiNode &node) {
466 aiNodeAnim *node_anim =
nullptr;
467 for (
size_t i = 0; i < anim.mNumChannels; ++i) {
468 if (anim.mChannels[i]->mNodeName == node.mName) {
469 node_anim = anim.mChannels[i];
475 <<
"Found channel for node: " << node.mName.C_Str() <<
"\n";
483 PTA_stdfloat tablex = PTA_stdfloat::empty_array(node_anim->mNumPositionKeys);
484 PTA_stdfloat tabley = PTA_stdfloat::empty_array(node_anim->mNumPositionKeys);
485 PTA_stdfloat tablez = PTA_stdfloat::empty_array(node_anim->mNumPositionKeys);
486 for (
size_t i = 0; i < node_anim->mNumPositionKeys; ++i) {
487 tablex[i] = node_anim->mPositionKeys[i].mValue.x;
488 tabley[i] = node_anim->mPositionKeys[i].mValue.y;
489 tablez[i] = node_anim->mPositionKeys[i].mValue.z;
491 group->set_table(
'x', tablex);
492 group->set_table(
'y', tabley);
493 group->set_table(
'z', tablez);
496 PTA_stdfloat tableh = PTA_stdfloat::empty_array(node_anim->mNumRotationKeys);
497 PTA_stdfloat tablep = PTA_stdfloat::empty_array(node_anim->mNumRotationKeys);
498 PTA_stdfloat tabler = PTA_stdfloat::empty_array(node_anim->mNumRotationKeys);
499 for (
size_t i = 0; i < node_anim->mNumRotationKeys; ++i) {
500 aiQuaternion ai_quat = node_anim->mRotationKeys[i].mValue;
501 LVecBase3 hpr = LQuaternion(ai_quat.w, ai_quat.x, ai_quat.y, ai_quat.z).get_hpr();
502 tableh[i] = hpr.get_x();
503 tablep[i] = hpr.get_y();
504 tabler[i] = hpr.get_z();
506 group->set_table(
'h', tableh);
507 group->set_table(
'p', tablep);
508 group->set_table(
'r', tabler);
511 PTA_stdfloat tablei = PTA_stdfloat::empty_array(node_anim->mNumScalingKeys);
512 PTA_stdfloat tablej = PTA_stdfloat::empty_array(node_anim->mNumScalingKeys);
513 PTA_stdfloat tablek = PTA_stdfloat::empty_array(node_anim->mNumScalingKeys);
514 for (
size_t i = 0; i < node_anim->mNumScalingKeys; ++i) {
515 tablei[i] = node_anim->mScalingKeys[i].mValue.x;
516 tablej[i] = node_anim->mScalingKeys[i].mValue.y;
517 tablek[i] = node_anim->mScalingKeys[i].mValue.z;
519 group->set_table(
'i', tablei);
520 group->set_table(
'j', tablej);
521 group->set_table(
'k', tablek);
525 <<
"No channel found for node: " << node.mName.C_Str() <<
"\n";
529 for (
size_t i = 0; i < node.mNumChildren; ++i) {
530 if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
531 create_anim_channel(anim, bundle, group, *node.mChildren[i]);
540 load_mesh(
size_t index) {
541 const aiMesh &mesh = *_scene->mMeshes[index];
545 if (mesh.HasBones()) {
547 <<
"Creating character for " << mesh.mName.C_Str() <<
"\n";
550 for (
size_t i = 0; i < mesh.mNumBones; ++i) {
551 const aiBone &bone = *mesh.mBones[i];
552 const aiNode *node = find_node(*_scene->mRootNode, bone.mName);
553 _bonemap[bone.mName.C_Str()] = node;
557 character =
new Character(mesh.mName.C_Str());
561 for (
size_t i = 0; i < mesh.mNumBones; ++i) {
562 const aiBone &bone = *mesh.mBones[i];
565 const aiNode *root = _bonemap[bone.mName.C_Str()];
566 while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
567 root = root->mParent;
571 if (character->
find_joint(root->mName.C_Str())) {
575 create_joint(character, bundle, skeleton, *root);
583 for (
size_t i = 0; i < mesh.mNumBones; ++i) {
584 const aiBone &bone = *mesh.mBones[i];
586 if (joint ==
nullptr) {
588 <<
"Could not find joint for bone: " << bone.mName.C_Str() <<
"\n";
594 for (
size_t j = 0; j < bone.mNumWeights; ++j) {
595 const aiVertexWeight &weight = bone.mWeights[j];
597 bone_weights[weight.mVertexId].push_back(BoneWeight(jvt, weight.mWeight));
604 aformat->
add_column(InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point);
605 if (mesh.HasNormals()) {
606 aformat->add_column(InternalName::get_normal(), 3, Geom::NT_stdfloat, Geom::C_vector);
608 if (mesh.HasVertexColors(0)) {
609 aformat->add_column(InternalName::get_color(), 4, Geom::NT_stdfloat, Geom::C_color);
611 unsigned int num_uvs = mesh.GetNumUVChannels();
614 aformat->add_column(InternalName::get_texcoord(), 3, Geom::NT_stdfloat, Geom::C_texcoord);
615 for (
unsigned int u = 1; u < num_uvs; ++u) {
618 aformat->add_column(InternalName::get_texcoord_name(out.str()), 3, Geom::NT_stdfloat, Geom::C_texcoord);
623 tb_aformat->
add_column(InternalName::make(
"transform_blend"), 1, Geom::NT_uint16, Geom::C_index);
626 for (
size_t i = 0; i < _scene->mNumAnimations; ++i) {
627 aiAnimation &ai_anim = *_scene->mAnimations[i];
628 bool convert_anim =
false;
631 <<
"Checking to see if anim (" << ai_anim.mName.C_Str() <<
") matches character (" << mesh.mName.C_Str() <<
")\n";
632 for (
size_t j = 0; j < ai_anim.mNumChannels; ++j) {
634 <<
"Searching for " << ai_anim.mChannels[j]->mNodeName.C_Str() <<
" in bone map" <<
"\n";
635 if (_bonemap.find(ai_anim.mChannels[j]->mNodeName.C_Str()) != _bonemap.end()) {
643 <<
"Found animation (" << ai_anim.mName.C_Str() <<
") for character (" << mesh.mName.C_Str() <<
")\n";
646 unsigned int frames = 0;
647 for (
size_t j = 0; j < ai_anim.mNumChannels; ++j) {
648 if (ai_anim.mChannels[j]->mNumPositionKeys > frames) {
649 frames = ai_anim.mChannels[j]->mNumPositionKeys;
651 if (ai_anim.mChannels[j]->mNumRotationKeys > frames) {
652 frames = ai_anim.mChannels[j]->mNumRotationKeys;
654 if (ai_anim.mChannels[j]->mNumScalingKeys > frames) {
655 frames = ai_anim.mChannels[j]->mNumScalingKeys;
658 PN_stdfloat fps = frames / (ai_anim.mTicksPerSecond * ai_anim.mDuration);
660 <<
"FPS " << fps <<
"\n";
662 <<
"Frames " << frames <<
"\n";
667 for (
size_t i = 0; i < mesh.mNumBones; ++i) {
668 const aiBone &bone = *mesh.mBones[i];
671 const aiNode *root = _bonemap[bone.mName.C_Str()];
672 while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
673 root = root->mParent;
677 if (root->mName == bone.mName) {
678 create_anim_channel(ai_anim, bundle, skeleton, *root);
682 character->add_child(bundle_node);
694 format->add_array(tb_aformat);
698 format->set_animation(aspec);
702 string name (mesh.mName.data, mesh.mName.length);
705 vdata->set_transform_blend_table(tbtable);
707 vdata->unclean_set_num_rows(mesh.mNumVertices);
711 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
712 const aiVector3D &vec = mesh.mVertices[i];
713 vertex.add_data3(vec.x, vec.y, vec.z);
717 if (mesh.HasNormals()) {
719 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
720 const aiVector3D &vec = mesh.mNormals[i];
721 normal.add_data3(vec.x, vec.y, vec.z);
726 if (mesh.HasVertexColors(0)) {
728 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
729 const aiColor4D &col = mesh.mColors[0][i];
730 color.add_data4(col.r, col.g, col.b, col.a);
738 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
739 const aiVector3D &vec = mesh.mTextureCoords[0][i];
740 texcoord0.add_data3(vec.x, vec.y, vec.z);
742 for (
unsigned int u = 1; u < num_uvs; ++u) {
745 GeomVertexWriter texcoord (vdata, InternalName::get_texcoord_name(out.str()));
746 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
747 const aiVector3D &vec = mesh.mTextureCoords[u][i];
748 texcoord.add_data3(vec.x, vec.y, vec.z);
755 GeomVertexWriter transform_blend (vdata, InternalName::get_transform_blend());
757 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
760 for (
size_t j = 0; j < bone_weights[i].size(); ++j) {
761 tblend.
add_transform(bone_weights[i][j].joint_vertex_xform, bone_weights[i][j].weight);
763 transform_blend.add_data1i(tbtable->add_blend(tblend));
777 for (
size_t i = 0; i < mesh.mNumFaces; ++i) {
778 const aiFace &face = mesh.mFaces[i];
780 if (face.mNumIndices == 0) {
783 }
else if (face.mNumIndices == 1) {
784 points->add_vertex(face.mIndices[0]);
785 points->close_primitive();
786 }
else if (face.mNumIndices == 2) {
787 lines->add_vertices(face.mIndices[0], face.mIndices[1]);
788 lines->close_primitive();
789 }
else if (face.mNumIndices == 3) {
790 triangles->add_vertices(face.mIndices[0], face.mIndices[1], face.mIndices[2]);
791 triangles->close_primitive();
793 nassertd(
false) continue;
799 if (points->get_num_primitives() > 0) {
802 if (lines->get_num_primitives() > 0) {
803 geom->add_primitive(lines);
805 if (triangles->get_num_primitives() > 0) {
806 geom->add_primitive(triangles);
809 _geoms[index] = geom;
810 _geom_matindices[index] = mesh.mMaterialIndex;
813 _charmap[mesh.mName.C_Str()] = character;
821 load_node(
const aiNode &node,
PandaNode *parent) {
826 if (_bonemap.find(node.mName.C_Str()) != _bonemap.end()) {
831 string name (node.mName.data, node.mName.length);
832 if (node.mNumMeshes > 0) {
838 if (_charmap.find(node.mName.C_Str()) != _charmap.end()) {
839 character = _charmap[node.mName.C_Str()];
840 parent->add_child(character);
842 parent->add_child(pnode);
846 const aiMatrix4x4 &t = node.mTransformation;
847 if (!t.IsIdentity()) {
848 LMatrix4 mat(t.a1, t.b1, t.c1, t.d1,
849 t.a2, t.b2, t.c2, t.d2,
850 t.a3, t.b3, t.c3, t.d3,
851 t.a4, t.b4, t.c4, t.d4);
852 pnode->set_transform(TransformState::make_mat(mat));
855 for (
size_t i = 0; i < node.mNumChildren; ++i) {
856 load_node(*node.mChildren[i], pnode);
859 if (node.mNumMeshes > 0) {
865 if (node.mNumMeshes == 1) {
866 meshIndex = node.mMeshes[0];
867 gnode->add_geom(_geoms[meshIndex]);
868 gnode->set_state(_mat_states[_geom_matindices[meshIndex]]);
870 for (
size_t i = 0; i < node.mNumMeshes; ++i) {
871 meshIndex = node.mMeshes[i];
872 gnode->add_geom(_geoms[node.mMeshes[i]],
873 _mat_states[_geom_matindices[meshIndex]]);
878 assimp_cat.debug() <<
"Adding char to geom\n";
879 character->add_child(gnode);
888 load_light(
const aiLight &light) {
889 string name (light.mName.data, light.mName.length);
890 assimp_cat.debug() <<
"Found light '" << name <<
"'\n";
895 switch (light.mType) {
896 case aiLightSource_DIRECTIONAL: {
898 _root->add_child(dlight);
900 col = light.mColorDiffuse;
901 dlight->set_color(LColor(col.r, col.g, col.b, 1));
903 col = light.mColorSpecular;
904 dlight->set_specular_color(LColor(col.r, col.g, col.b, 1));
906 vec = light.mPosition;
907 dlight->set_point(LPoint3(vec.x, vec.y, vec.z));
909 vec = light.mDirection;
910 dlight->set_direction(LVector3(vec.x, vec.y, vec.z));
913 case aiLightSource_POINT: {
915 _root->add_child(plight);
917 col = light.mColorDiffuse;
918 plight->set_color(LColor(col.r, col.g, col.b, 1));
920 col = light.mColorSpecular;
921 plight->set_specular_color(LColor(col.r, col.g, col.b, 1));
923 vec = light.mPosition;
924 plight->set_point(LPoint3(vec.x, vec.y, vec.z));
926 plight->set_attenuation(LVecBase3(light.mAttenuationConstant,
927 light.mAttenuationLinear,
928 light.mAttenuationQuadratic));
931 case aiLightSource_SPOT: {
933 _root->add_child(plight);
935 col = light.mColorDiffuse;
936 plight->set_color(LColor(col.r, col.g, col.b, 1));
938 col = light.mColorSpecular;
939 plight->set_specular_color(LColor(col.r, col.g, col.b, 1));
941 plight->set_attenuation(LVecBase3(light.mAttenuationConstant,
942 light.mAttenuationLinear,
943 light.mAttenuationQuadratic));
945 plight->get_lens()->set_fov(light.mAngleOuterCone);
949 vec = light.mDirection;
950 LPoint3 pos (light.mPosition.x, light.mPosition.y, light.mPosition.z);
952 ::look_at(quat, LPoint3(vec.x, vec.y, vec.z), LVector3::up());
953 plight->set_transform(TransformState::make_pos_quat_scale(pos, quat, LVecBase3(1, 1, 1)));
963 assimp_cat.warning() <<
"Light '" << name <<
"' has an unknown type!\n";
968 col = light.mColorAmbient;
969 LVecBase4 ambient (col.r, col.g, col.b, 0);
970 if (ambient != LVecBase4::zero()) {
972 alight->set_color(ambient);
973 _root->add_child(alight);