/*! * \internal * * \return A new mesh object containing the mesh in \p node, or NULL if no such * mesh can be found. */ dcollide::Shape* Loader3dsInternal::createShape(Lib3dsNode* node, Lib3dsMatrix* translateRotateMatrix) { if (!node) { return 0; } if (node->type != LIB3DS_OBJECT_NODE) { return 0; } if (strcmp(node->name, "$$$DUMMY") == 0) { // AB: nodes with this name are only transformation nodes, i.e. they // don't have a mesh, only a matrix. return 0; } Lib3dsMesh* mesh = lib3ds_file_mesh_by_name(mFile, node->name); if (!mesh) { std::cout << "Cannot find mesh " << node->name << " in 3ds file" << std::endl; return 0; } if (mesh->faces < 1) { std::cerr << "No faces in mesh " << node->name << std::endl; return 0; } if (mesh->points < 3) { std::cerr << "Less than 3 points in mesh " << node->name << std::endl; return 0; } Lib3dsMatrix origMeshMatrix; lib3ds_matrix_copy(origMeshMatrix, mesh->matrix); lib3ds_matrix_inv(origMeshMatrix); // 3ds stores inverted mesh matrix dcollide::Matrix meshMatrix(&origMeshMatrix[0][0]); // AB: Ogre does not apply "scale" values to child nodes, lib3ds does. // so to display the model correctly we remove the scale completely // (we integrate it directly into the vertices). // to do this: // let M:=the lib3ds matrix the point is normally transformed by // (i.e. including the parent-node matrix) // let M':=the matrix d-collide will use (i.e. // translation+rotation only, no scale) // then for every vertex v the correct transformed position p is: // Mv=p // we search for a vertex v' so that: // M'v'=p // since we have M and v (and thus p) and M' we can do this like // this: // v'=(M'^-1)p // which equals: // v'=(M'^-1)Mv dcollide::Matrix nodeMatrix(&node->matrix[0][0]); // M Lib3dsMatrix invertedTranslateRotate3ds; lib3ds_matrix_copy(invertedTranslateRotate3ds, *translateRotateMatrix); lib3ds_matrix_inv(invertedTranslateRotate3ds); dcollide::Matrix invertedTranslateRotate(&invertedTranslateRotate3ds[0][0]); // M'^-1 dcollide::Matrix removeScaleMatrix(invertedTranslateRotate); removeScaleMatrix.multiply(&nodeMatrix); Lib3dsObjectData* data = &node->data.object; std::vector<dcollide::Vertex*> vertices(mesh->points); for (unsigned int i = 0; i < mesh->points; i++) { Lib3dsPoint* p = &mesh->pointL[i]; dcollide::Vector3 meshPos; meshMatrix.transform(&meshPos, dcollide::Vector3( p->pos[0] - data->pivot[0], p->pos[1] - data->pivot[1], p->pos[2] - data->pivot[2])); dcollide::Vector3 pos; removeScaleMatrix.transform(&pos, meshPos); vertices[i] = new dcollide::Vertex(pos); } std::vector<int> indices(mesh->faces * 3); for (unsigned int i = 0; i < mesh->faces; i++) { Lib3dsFace* f = &mesh->faceL[i]; indices[i * 3 + 0] = f->points[0]; indices[i * 3 + 1] = f->points[1]; indices[i * 3 + 2] = f->points[2]; } dcollide::Mesh* newMesh = new dcollide::Mesh(vertices, indices); return newMesh; }
/*! * See \ref Loader3ds::loadFromFileToOneMesh */ dcollide::Mesh* Loader3dsInternal::loadFromFileToOneMesh(const char* fileName, TextureInformation* textureInformation) { // AB: // we cannot load texture information here, because we are merging all // meshes into a single one. // -> adjusting the texels may still be possible, however if the model // uses > 1 texture, we can't change that. mData->mProxy2Transformation.clear(); mData->mProxy2TextureInformation.clear(); if (!fileName) { throw dcollide::NullPointerException("fileName"); } mFile = lib3ds_file_load(fileName); if (!mFile) { std::cout << dc_funcinfo << "unable to load " << fileName << std::endl; return 0; } // AB: some files don't store nodes and just want exactly one node per mesh. // atm we don't support that. if (!mFile->nodes) { std::cout << dc_funcinfo << "File " << fileName << " does not contain any nodes. mesh-only files not supported currently." << std::endl; lib3ds_file_free(mFile); mFile = 0; return 0; } // 3ds stores several frames, we want the first lib3ds_file_eval(mFile, 0); std::list<Lib3dsNode*> nodes; Lib3dsNode* node = mFile->nodes; while (node) { nodes.push_back(node); node = node->next; } bool texelLoadError = false; std::vector<dcollide::Vector3> texels; std::vector<dcollide::Vertex*> vertices; std::vector<dcollide::Triangle*> triangles; std::vector<int> indices; while (!nodes.empty()) { Lib3dsNode* node = nodes.front(); nodes.pop_front(); for (Lib3dsNode* n = node->childs; n; n = n->next) { nodes.push_back(n); } // node->type can be object, light, camera, ... // -> only object nodes are relevant to us if (node->type != LIB3DS_OBJECT_NODE) { continue; } if (strcmp(node->name, "$$$DUMMY") == 0) { // AB: nodes with this name are only transformation nodes, i.e. they // don't have a mesh, only a matrix. continue; } unsigned int pointOffset = vertices.size(); Lib3dsMesh* mesh = lib3ds_file_mesh_by_name(mFile, node->name); Lib3dsMatrix origMeshMatrix; lib3ds_matrix_copy(origMeshMatrix, mesh->matrix); lib3ds_matrix_inv(origMeshMatrix); // 3ds stores inverted mesh matrix dcollide::Matrix meshMatrix(&origMeshMatrix[0][0]); dcollide::Matrix nodeMatrix(&node->matrix[0][0]); Lib3dsObjectData* data = &node->data.object; nodeMatrix.translate(dcollide::Vector3(-data->pivot[0], -data->pivot[1], -data->pivot[2])); dcollide::Matrix matrix = nodeMatrix; matrix.multiply(&meshMatrix); for (unsigned int i = 0; i < mesh->points; i++) { Lib3dsPoint* p = &mesh->pointL[i]; dcollide::Vector3 pos; matrix.transform(&pos, dcollide::Vector3( p->pos[0], p->pos[1], p->pos[2] )); vertices.push_back(new dcollide::Vertex(pos)); } for (unsigned int i = 0; i < mesh->faces; i++) { Lib3dsFace* f = &mesh->faceL[i]; indices.push_back(f->points[0] + pointOffset); indices.push_back(f->points[1] + pointOffset); indices.push_back(f->points[2] + pointOffset); } if (textureInformation) { TextureInformation t = loadTextureInformation(node); const std::vector<dcollide::Vector3>& nodeTexels = t.getTexels(); if (mesh->texelL && nodeTexels.size() != mesh->texels) { dcollide::warning() << "texturing problem in " << fileName; dcollide::warning() << "invalid texel count loaded: have=" << nodeTexels.size() << " expected=" << mesh->texels; dcollide::warning() << "adding dummy texels..."; for (unsigned int i = 0; i < mesh->texels; i++) { texels.push_back(dcollide::Vector3(0.0, 0.0, 0.0)); } // texelLoadError = true; } else { for (unsigned int i = 0; i < nodeTexels.size(); i++) { texels.push_back(nodeTexels[i]); } } } } if (textureInformation) { if (!texelLoadError) { textureInformation->setTextured(true); textureInformation->setTextureFileName("deformable.tga"); textureInformation->setTexels(texels); } else { textureInformation->setTextured(false); } } lib3ds_file_free(mFile); mFile = 0; dcollide::Mesh* mesh = new dcollide::Mesh(vertices, indices); return mesh; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::connectNodes( MObject modifierNode ) // -------------------------------------------------------------------------------------------- // // Description: // // This method connects up the modifier nodes, while accounting for DG factors // such as construction history and tweaks. The method has a series of steps which // it runs through to process nodes under varying circumstances: // // 1) Gather meshNode connection data (ie. attributes and plugs) // // 2) Gather upstreamNode data - This is history-dependent. If the node has history, // an actual upstreamNode exists and that is used to // drive the input of our modifierNode. // // Otherwise, if the node ds not have history, the // meshNode is duplicated, set as an intermediate object // and regarded as our new upstreamNode which will drive // the input of our modifierNode. The case with history // already has this duplicate meshNode at the top, driving // all other history nodes and serving as a reference // to the "original state" of the node before any // modifications. // // 3) Gather modifierNode connection data // // 4) Process tweak data (if it exists) - This is history-dependent. If there is // history, the tweak data is extracted and deleted // from the meshNode and encapsulated inside a // polyTweak node. The polyTweak node is then // inserted ahead of the modifier node. // // If there is no history, the same is done as // in the history case, except the tweaks are // deleted from the duplicate meshNode in addition // to the actual meshNode. // // 5) Connect the nodes // // 6) Collapse/Bake nodes into the actual meshNode if the meshNode had no previous // construction history and construction history recording is turned off. // (ie. (!fHasHistory && !fHasRecordHistory) == true ) // { MStatus status; // Declare our internal processing data structure (see polyModifierCmd.h for definition) // modifyPolyData data; //->jetzt als ElementVariable // Get the mesh node, plugs and attributes // status = processMeshNode( data ); MCheckStatus( status, "processMeshNode" ); // Get upstream node, plugs and attributes // status = processUpstreamNode( data ); MCheckStatus( status, "processUpstreamNode" ); // Get the modifierNode attributes // status = processModifierNode( modifierNode, data ); MCheckStatus( status, "processModifierNode" ); // Process tweaks on the meshNode // status = processTweaks( data ); MCheckStatus( status, "processTweaks" ); if( fHasTweaks ) { status = fDGModifier.connect( data.upstreamNodeShape, data.upstreamNodeSrcAttr, data.tweakNode, data.tweakNodeDestAttr ); MCheckStatus( status, "upstream-tweak connect failed" ); status = fDGModifier.connect( data.tweakNode, data.tweakNodeSrcAttr, modifierNode, data.modifierNodeDestAttr ); MCheckStatus( status, "tweak-modifier connect failed" ); } else { //hier muessen die Plugs verwendet werden, weil die Attribute eventuell multis sind MPlug destPlug(modifierNode,data.modifierNodeDestAttr ); INVIS(cout<<data.upstreamNodeSrcPlug.name().asChar()<<" --> "<<destPlug.name().asChar()<<endl); status = fDGModifier.connect( data.upstreamNodeSrcPlug, destPlug ); MCheckStatus( status, "upstream-modifier connect failed" ); } // outMesh mit inputMesh verbinden // fDGModifier.connect(MPlug(modifierNode,data.modifierNodeSrcAttr), data.meshNodeDestPlug); // Ausserdem das MatrixAttribut des Meshes mit dem meshMatrix Attr der Node verbinden // MFnDependencyNode depFn( modifierNode ); MPlug meshMatrix( modifierNode, depFn.attribute("meshMatrix") ); depFn.setObject(data.meshNodeTransform); MPlug shapeMatrix( data.meshNodeTransform, depFn.attribute("worldMatrix") ); fDGModifier.connect(shapeMatrix.elementByLogicalIndex( 0 ), meshMatrix ); // Jetzt die ModifierNode mit der VisNode connecten /* status = fDGModifier.connect( modifierNode, data.modifierNodeSrcAttr, data.meshNodeShape, data.meshNodeDestAttr ); */ // MCheckStatus( status, "modifier-mesh connect failed" ); status = fDGModifier.doIt(); MCheckStatus( status, "modifier-mesh DOIT failed" ); if(createAnimCurves) { //AnimCurve erstellen(dies ist nur hier moeglich, da die Node erst nach dem DoIt wirklich existiert (scheinbar) MFnAnimCurve aCurve; MFnDependencyNode myDepNodeFn(modifierNode); aCurve.create(modifierNode,myDepNodeFn.attribute("csl"),MFnAnimCurve::kAnimCurveUU,&createSlideAnim,&status); } return status; }