void calc_bind_pose(void) { // we now (in the single mesh / non-baking case) have our bind pose // our invpose is set to the inv_bind_pose matrix // compute forward abspose and pose matrices here int i; for (i = 0; i < numbones; i++) { if (bonelist[i].isskin) { // skinned and boned, invpose is our reference aiInverseMatrix(&bonelist[i].abspose, &bonelist[i].invpose); bonelist[i].pose = bonelist[i].abspose; if (bonelist[i].parent >= 0) { struct aiMatrix4x4 m = bonelist[bonelist[i].parent].invpose; aiMultiplyMatrix4(&m, &bonelist[i].pose); bonelist[i].pose = m; } } else { // not skinned, so no invpose. pose is our reference bonelist[i].pose = bonelist[i].node->mTransformation; bonelist[i].abspose = bonelist[i].pose; if (bonelist[i].parent >= 0) { bonelist[i].abspose = bonelist[bonelist[i].parent].abspose; aiMultiplyMatrix4(&bonelist[i].abspose, &bonelist[i].pose); } aiInverseMatrix(&bonelist[i].invpose, &bonelist[i].abspose); } } // compute translate/rotate/scale for (i = 0; i < numbones; i++) if (bonelist[i].isbone) aiDecomposeMatrix(&bonelist[i].pose, &bonelist[i].scale, &bonelist[i].rotate, &bonelist[i].translate); }
void fix_pose(void) { int i; calc_abs_pose(); if (dohips) fix_hips(0); for (i = 0; i < numbones; i++) { if (bonelist[i].isbone) { // remove scaling factor in absolute pose if (dounscale < 0) { struct aiVector3D apos, ascale; struct aiQuaternion arot; aiDecomposeMatrix(&bonelist[i].abspose, &ascale, &arot, &apos); bonelist[i].unscale[0] = ascale.x; bonelist[i].unscale[1] = ascale.y; bonelist[i].unscale[2] = ascale.z; if (KILL(ascale.x) != 1 || KILL(ascale.y) != 1 || KILL(ascale.z) != 1) fprintf(stderr, "unscaling %s: %g %g %g\n", bonelist[i].name, ascale.x, ascale.y, ascale.z); } if (dounscale) { float x = bonelist[i].unscale[0]; float y = bonelist[i].unscale[1]; float z = bonelist[i].unscale[2]; if (KILL(x) != 1 || KILL(y) != 1 || KILL(z) != 1) { bonelist[i].abspose.a1 /= x; bonelist[i].abspose.b1 /= x; bonelist[i].abspose.c1 /= x; bonelist[i].abspose.a2 /= y; bonelist[i].abspose.b2 /= y; bonelist[i].abspose.c2 /= y; bonelist[i].abspose.a3 /= z; bonelist[i].abspose.b3 /= z; bonelist[i].abspose.c3 /= z; } } // flip axis in absolute pose if (doaxis) aiMultiplyMatrix4(&bonelist[i].abspose, &axis_x_to_y); // ...and invert so we can recalculate the local poses aiInverseMatrix(&bonelist[i].invpose, &bonelist[i].abspose); // ...and recalculate the local pose bonelist[i].pose = bonelist[i].abspose; if (bonelist[i].parent >= 0) { struct aiMatrix4x4 m = bonelist[bonelist[i].parent].invpose; aiMultiplyMatrix4(&m, &bonelist[i].pose); bonelist[i].pose = m; } // ...and make sure we have it in decomposed form aiDecomposeMatrix(&bonelist[i].pose, &bonelist[i].scale, &bonelist[i].rotate, &bonelist[i].translate); } } if (dohips) unfix_hips(); }
void get_bounding_box_for_node (const struct aiScene *sc, const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo) { struct aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = sc->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { struct aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); min->y = aisgl_min(min->y,tmp.y); min->z = aisgl_min(min->z,tmp.z); max->x = aisgl_max(max->x,tmp.x); max->y = aisgl_max(max->y,tmp.y); max->z = aisgl_max(max->z,tmp.z); } } for (n = 0; n < nd->mNumChildren; ++n) { get_bounding_box_for_node(sc, nd->mChildren[n],min,max,trafo); } *trafo = prev; }
/*! * \brief Go through the scene nodes and load and transform all meshes them. * \author Sascha Kaden * \param[in] scene * \param[in] node * \param[in] transformation * \param[out] vector of meshes * \date 2017-05-09 */ void getMeshes(const aiScene *scene, const aiNode *node, aiMatrix4x4 *trafo, std::vector<Mesh> &meshes, const bool useTrafo) { aiMatrix4x4 prevTrafo; prevTrafo = *trafo; aiMultiplyMatrix4(trafo, &node->mTransformation); for (size_t i = 0; i < node->mNumMeshes; ++i) { Mesh mesh; const aiMesh *aimesh = scene->mMeshes[node->mMeshes[i]]; for (size_t j = 0; j < aimesh->mNumVertices; ++j) { aiVector3D vertex = aimesh->mVertices[j]; if (useTrafo) aiTransformVecByMatrix4(&vertex, trafo); mesh.vertices.emplace_back(vertex.x, vertex.y, vertex.z); } for (size_t j = 0; j < aimesh->mNumFaces; ++j) { if (aimesh->mFaces[j].mNumIndices > 2) { mesh.faces.emplace_back(aimesh->mFaces[j].mIndices[0], aimesh->mFaces[j].mIndices[1], aimesh->mFaces[j].mIndices[2]); } else { Logging::warning("Face array is to short", "CadProcessing"); } } meshes.push_back(mesh); } for (size_t i = 0; i < node->mNumChildren; ++i) { getMeshes(scene, node->mChildren[i], trafo, meshes); } *trafo = prevTrafo; }
//------------------------------------------- void ofxAssimpModelLoader::getBoundingBoxForNode(const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo) { struct aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n){ const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t){ struct aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = MIN(min->x,tmp.x); min->y = MIN(min->y,tmp.y); min->z = MIN(min->z,tmp.z); max->x = MAX(max->x,tmp.x); max->y = MAX(max->y,tmp.y); max->z = MAX(max->z,tmp.z); } } for (n = 0; n < nd->mNumChildren; ++n){ this->getBoundingBoxForNode(nd->mChildren[n], min, max, trafo); } *trafo = prev; }
void AssimpScene::recursive_getBoundingBox( const aiScene *scene, const aiNode* nd, aiVector3D & sceneMin, aiVector3D & sceneMax, aiMatrix4x4* sceneMatrix) { aiMatrix4x4 sceneMatrixOriginal = *sceneMatrix; aiMultiplyMatrix4(sceneMatrix, & nd->mTransformation); for (int n=0; n < nd->mNumMeshes; n++) { aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (int t = 0; t < mesh->mNumVertices; t++) { aiVector3D vert = mesh->mVertices[t]; aiTransformVecByMatrix4(&vert, sceneMatrix); sceneMin.x = std::min(sceneMin.x, vert.x); sceneMin.y = std::min(sceneMin.y, vert.y); sceneMin.z = std::min(sceneMin.z, vert.z); sceneMax.x = std::max(sceneMax.x, vert.x); sceneMax.y = std::max(sceneMax.y, vert.y); sceneMax.z = std::max(sceneMax.z, vert.z); } } //std::cout << "AssimpScene SceneMin " << sceneMin.x << " , " << sceneMin.y << " , " << sceneMin.z << std::endl; //std::cout << "AssimpScene SceneMax " << sceneMax.x << " , " << sceneMax.y << " , " << sceneMax.z << std::endl; for (int n = 0; n < nd->mNumChildren; n++) { recursive_getBoundingBox(scene,nd->mChildren[n], sceneMin, sceneMax,sceneMatrix); } *sceneMatrix = sceneMatrixOriginal; }
void AssimpSimpleModelLoader::get_bounding_box_for_node (const aiNode* nd, aiVector3D* min, aiVector3D* max, aiMatrix4x4* trafo ){ aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { const aiMesh* mesh = this->scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); min->y = aisgl_min(min->y,tmp.y); min->z = aisgl_min(min->z,tmp.z); max->x = aisgl_max(max->x,tmp.x); max->y = aisgl_max(max->y,tmp.y); max->z = aisgl_max(max->z,tmp.z); } } for (n = 0; n < nd->mNumChildren; ++n) { get_bounding_box_for_node(nd->mChildren[n],min,max,trafo); } *trafo = prev; }
void Model3D::get_bounding_box_for_node(const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo) { struct aiMatrix4x4 prev; // Use struct keyword to show you want struct version of this, not normal typedef? unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo, &nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { struct aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp, trafo); min->x = aisgl_min(min->x,tmp.x); min->y = aisgl_min(min->y,tmp.y); min->z = aisgl_min(min->z,tmp.z); max->x = aisgl_max(max->x,tmp.x); max->y = aisgl_max(max->y,tmp.y); max->z = aisgl_max(max->z,tmp.z); } } for (n = 0; n < nd->mNumChildren; ++n) get_bounding_box_for_node(nd->mChildren[n], min, max, trafo); *trafo = prev; }
// recalculate abspose from local pose matrix void calc_abs_pose(void) { int i; for (i = 0; i < numbones; i++) { bonelist[i].abspose = bonelist[i].pose; if (bonelist[i].parent >= 0) { bonelist[i].abspose = bonelist[bonelist[i].parent].abspose; aiMultiplyMatrix4(&bonelist[i].abspose, &bonelist[i].pose); } } }
void bake_mesh_skin(const struct aiMesh *mesh) { int i, k, b; struct aiMatrix3x3 mat3; struct aiMatrix4x4 bonemat[1000], mat; struct aiVector3D *outpos, *outnorm; if (mesh->mNumBones == 0) return; outpos = malloc(mesh->mNumVertices * sizeof *outpos); outnorm = malloc(mesh->mNumVertices * sizeof *outnorm); memset(outpos, 0, mesh->mNumVertices * sizeof *outpos); memset(outnorm, 0, mesh->mNumVertices * sizeof *outpos); calc_abs_pose(); for (i = 0; i < mesh->mNumBones; i++) { b = find_bone(mesh->mBones[i]->mName.data); bonemat[i] = bonelist[b].abspose; aiMultiplyMatrix4(&bonemat[i], &mesh->mBones[i]->mOffsetMatrix); } for (k = 0; k < mesh->mNumBones; k++) { struct aiBone *bone = mesh->mBones[k]; b = find_bone(mesh->mBones[k]->mName.data); mat = bonemat[k]; mat3.a1 = mat.a1; mat3.a2 = mat.a2; mat3.a3 = mat.a3; mat3.b1 = mat.b1; mat3.b2 = mat.b2; mat3.b3 = mat.b3; mat3.c1 = mat.c1; mat3.c2 = mat.c2; mat3.c3 = mat.c3; for (i = 0; i < bone->mNumWeights; i++) { struct aiVertexWeight vw = bone->mWeights[i]; int v = vw.mVertexId; float w = vw.mWeight; struct aiVector3D srcpos = mesh->mVertices[v]; struct aiVector3D srcnorm = mesh->mNormals[v]; aiTransformVecByMatrix4(&srcpos, &mat); aiTransformVecByMatrix3(&srcnorm, &mat3); outpos[v].x += srcpos.x * w; outpos[v].y += srcpos.y * w; outpos[v].z += srcpos.z * w; outnorm[v].x += srcnorm.x * w; outnorm[v].y += srcnorm.y * w; outnorm[v].z += srcnorm.z * w; } } memcpy(mesh->mVertices, outpos, mesh->mNumVertices * sizeof *outpos); memcpy(mesh->mNormals, outnorm, mesh->mNumVertices * sizeof *outnorm); free(outpos); free(outnorm); }
void aiComposeMatrix(struct aiMatrix4x4 *m, struct aiVector3D *scale, struct aiQuaternion *q, struct aiVector3D *pos) { struct aiMatrix4x4 smat; aiIdentityMatrix4(m); m->a1 = 1.0f - 2.0f * (q->y * q->y + q->z * q->z); m->a2 = 2.0f * (q->x * q->y - q->z * q->w); m->a3 = 2.0f * (q->x * q->z + q->y * q->w); m->b1 = 2.0f * (q->x * q->y + q->z * q->w); m->b2 = 1.0f - 2.0f * (q->x * q->x + q->z * q->z); m->b3 = 2.0f * (q->y * q->z - q->x * q->w); m->c1 = 2.0f * (q->x * q->z - q->y * q->w); m->c2 = 2.0f * (q->y * q->z + q->x * q->w); m->c3 = 1.0f - 2.0f * (q->x * q->x + q->y * q->y); aiIdentityMatrix4(&smat); smat.a1 = scale->x; smat.b2 = scale->y; smat.c3 = scale->z; aiMultiplyMatrix4(m, &smat); m->a4 = pos->x; m->b4 = pos->y; m->c4 = pos->z; }
void export_node(FILE *out, const struct aiScene *scene, const struct aiNode *node, struct aiMatrix4x4 mat, char *clean_name) { struct aiMatrix3x3 mat3; int i, a, k, t; aiMultiplyMatrix4(&mat, &node->mTransformation); mat3.a1 = mat.a1; mat3.a2 = mat.a2; mat3.a3 = mat.a3; mat3.b1 = mat.b1; mat3.b2 = mat.b2; mat3.b3 = mat.b3; mat3.c1 = mat.c1; mat3.c2 = mat.c2; mat3.c3 = mat.c3; if (!strstr(node->mName.data, "$ColladaAutoName$")) clean_name = clean_node_name((char*)node->mName.data); if (only_one_node && strcmp(clean_name, only_one_node)) goto skip_mesh; for (i = 0; i < node->mNumMeshes; i++) { struct aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; struct aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; if (mesh->mNumBones == 0 && dobone && !dorigid) { if (verbose) fprintf(stderr, "skipping rigid mesh %d in node %s (no bones)\n", i, clean_name); continue; } fprintf(stderr, "exporting mesh %s[%d]: %d vertices, %d faces\n", clean_name, i, mesh->mNumVertices, mesh->mNumFaces); fprintf(out, "\n"); fprintf(out, "mesh \"%s\"\n", clean_name); fprintf(out, "material \"%s\"\n", find_material(material)); struct vb *vb = (struct vb*) malloc(mesh->mNumVertices * sizeof(*vb)); memset(vb, 0, mesh->mNumVertices * sizeof(*vb)); // A rigidly animated node -- insert fake blend index/weights if (mesh->mNumBones == 0 && dobone) { a = find_bone((char*)node->mName.data); if (verbose) fprintf(stderr, "\trigid bone %d for mesh in node %s (no bones)\n", bonelist[a].number, node->mName.data); for (k = 0; k < mesh->mNumVertices; k++) { vb[k].b[0] = bonelist[a].number; vb[k].w[0] = 1; vb[k].n = 1; } } // Assemble blend index/weight array for (k = 0; k < mesh->mNumBones; k++) { struct aiBone *bone = mesh->mBones[k]; a = find_bone(bone->mName.data); for (t = 0; t < bone->mNumWeights; t++) { struct aiVertexWeight *w = mesh->mBones[k]->mWeights + t; int idx = w->mVertexId; if (vb[idx].n < MAXBLEND) { vb[idx].b[vb[idx].n] = bonelist[a].number; vb[idx].w[vb[idx].n] = w->mWeight; vb[idx].n++; } } } for (k = 0; k < mesh->mNumVertices; k++) { struct aiVector3D vp = mesh->mVertices[k]; if (!dobone) aiTransformVecByMatrix4(&vp, &mat); fprintf(out, "vp %.9g %.9g %.9g\n", vp.x, vp.y, vp.z); if (mesh->mNormals) { struct aiVector3D vn = mesh->mNormals[k]; if (!dobone) aiTransformVecByMatrix3(&vn, &mat3); fprintf(out, "vn %.9g %.9g %.9g\n", vn.x, vn.y, vn.z); } if (mesh->mTextureCoords[0]) { float u = mesh->mTextureCoords[0][k].x; float v = 1 - mesh->mTextureCoords[0][k].y; fprintf(out, "vt %.9g %.9g\n", u, v); } for (t = 1; t <= MAX_UVMAP; t++) { if (mesh->mTextureCoords[t]) { float u = mesh->mTextureCoords[t][k].x; float v = 1 - mesh->mTextureCoords[t][k].y; fprintf(out, "v%d %.9g %.9g\n", FIRST_UVMAP+t-1, u, v); } } if (mesh->mColors[0]) { float r = mesh->mColors[0][k].r; r = floorf(r * 255) / 255; float g = mesh->mColors[0][k].g; g = floorf(g * 255) / 255; float b = mesh->mColors[0][k].b; b = floorf(b * 255) / 255; float a = mesh->mColors[0][k].a; a = floorf(a * 255) / 255; fprintf(out, "vc %.9g %.9g %.9g %.9g\n", r, g, b, a); } for (t = 1; t <= MAX_COL; t++) { if (mesh->mColors[t]) { float r = mesh->mColors[t][k].r; r = floorf(r * 255) / 255; float g = mesh->mColors[t][k].g; g = floorf(g * 255) / 255; float b = mesh->mColors[t][k].b; b = floorf(b * 255) / 255; float a = mesh->mColors[t][k].a; a = floorf(a * 255) / 255; fprintf(out, "v%d %.9g %.9g %.9g %.9g\n", FIRST_COL+t-1, r, g, b, a); } } if (dobone) { fprintf(out, "vb"); for (t = 0; t < vb[k].n; t++) { fprintf(out, " %d %.9g", vb[k].b[t], vb[k].w[t]); } fprintf(out, "\n"); } } for (k = 0; k < mesh->mNumFaces; k++) { struct aiFace *face = mesh->mFaces + k; if (face->mNumIndices == 3) { if (doflip) fprintf(out, "fm %d %d %d\n", face->mIndices[2], face->mIndices[1], face->mIndices[0]); else fprintf(out, "fm %d %d %d\n", face->mIndices[0], face->mIndices[1], face->mIndices[2]); } else if (face->mNumIndices == 4) { if (doflip) fprintf(out, "fm %d %d %d %d\n", face->mIndices[3], face->mIndices[2], face->mIndices[1], face->mIndices[0]); else fprintf(out, "fm %d %d %d %d\n", face->mIndices[0], face->mIndices[1], face->mIndices[2], face->mIndices[3]); } else if (face->mNumIndices > 4) { fprintf(stderr, "n-gon (%d) in mesh!\n", face->mNumIndices); int i1 = face->mIndices[0]; int i2 = face->mIndices[1]; for (a = 2; a < face->mNumIndices; a++) { int i3 = face->mIndices[a]; if (doflip) fprintf(out, "fm %d %d %d\n", i3, i2, i1); else fprintf(out, "fm %d %d %d\n", i1, i2, i3); i2 = i3; } } else { fprintf(stderr, "skipping point/line primitive\n"); } } free(vb); } skip_mesh: for (i = 0; i < node->mNumChildren; i++) export_node(out, scene, node->mChildren[i], mat, clean_name); }
int main(int argc, char **argv) { FILE *file; const struct aiScene *scene; char *p; int c; char *output = NULL; char *input = NULL; int onlyanim = 0; int onlymesh = 0; while ((c = getopt(argc, argv, "AHMPSabflmn:o:rvxsu:")) != -1) { switch (c) { case 'A': save_all_bones++; break; case 'H': dohips = 1; break; case 'M': list_all_meshes = 1; break; case 'P': list_all_positions = 1; break; case 'S': dostatic = 1; break; case 'a': onlyanim = 1; break; case 'm': onlymesh = 1; break; case 'n': only_one_node = optarg++; break; case 'b': need_to_bake_skin = 1; break; case 'o': output = optarg++; break; case 'f': doflip = 0; break; case 'r': dorigid = 1; break; case 'l': dolowprec = 1; break; case 'v': verbose++; break; case 'x': doaxis = 1; break; case 's': dounscale = 1; break; case 'u': untaglist[numuntags++] = optarg++; break; default: usage(); break; } } if (optind == argc) usage(); input = argv[optind++]; p = strrchr(input, '/'); if (!p) p = strrchr(input, '\\'); if (!p) p = input; else p++; strcpy(basename, p); p = strrchr(basename, '.'); if (p) *p = 0; numtags = argc - optind; taglist = argv + optind; /* Read input file and post process */ int flags = 0; flags |= aiProcess_JoinIdenticalVertices; flags |= aiProcess_GenSmoothNormals; flags |= aiProcess_GenUVCoords; flags |= aiProcess_TransformUVCoords; flags |= aiProcess_LimitBoneWeights; //flags |= aiProcess_FindInvalidData; flags |= aiProcess_ImproveCacheLocality; //flags |= aiProcess_RemoveRedundantMaterials; //flags |= aiProcess_OptimizeMeshes; fprintf(stderr, "loading %s\n", input); scene = aiImportFile(input, flags); if (!scene) { fprintf(stderr, "cannot import '%s': %s\n", input, aiGetErrorString()); exit(1); } if (scene->mNumAnimations > 0) doanim = 1; if (onlymesh) { domesh = 1; doanim = 0; } if (onlyanim) { domesh = 0; doanim = 1; } if (getenv("DOANIM")) doanim = 1; // Convert to Z-UP coordinate system aiMultiplyMatrix4(&scene->mRootNode->mTransformation, &yup_to_zup); // Build a list of bones and compute the bind pose matrices. if (build_bone_list(scene) > 0) dobone = 1; if (dostatic) { dobone = 0; need_to_bake_skin = 0; } if (list_all_meshes) { export_mesh_list(scene); return 0; } if (list_all_positions) { export_position_list(scene); return 0; } // Mesh is split with incompatible bind matrices, so pick a new // bind pose and deform the mesh to fit. if (need_to_bake_skin && !onlyanim) { apply_initial_frame(); // ditch original bind pose bake_scene_skin(scene); } /* * Export scene as mesh/skeleton/animation */ if (output) { fprintf(stderr, "saving %s\n", output); file = fopen(output, "w"); if (!file) { fprintf(stderr, "cannot open output file: '%s'\n", output); exit(1); } } else { file = stdout; } fprintf(file, "# Inter-Quake Export\n"); if (dobone) { export_bone_list(file); } if (domesh) { struct aiMatrix4x4 identity; aiIdentityMatrix4(&identity); export_custom_vertexarrays(file, scene); export_node(file, scene, scene->mRootNode, identity, "SCENE"); } if (dobone) { if (doanim) { export_animations(file, scene); } } if (output) fclose(file); aiReleaseImport(scene); return 0; }