// ob should be of type OB_MESH // both args are required void ArmatureExporter::export_controller(Object* ob, Object *ob_arm) { // joint names // joint inverse bind matrices // vertex weights // input: // joint names: ob -> vertex group names // vertex group weights: me->dvert -> groups -> index, weight /* me->dvert: typedef struct MDeformVert { struct MDeformWeight *dw; int totweight; int flag; // flag only in use for weightpaint now } MDeformVert; typedef struct MDeformWeight { int def_nr; float weight; } MDeformWeight; */ Mesh *me = (Mesh*)ob->data; if (!me->dvert) return; std::string controller_name = id_name(ob_arm); std::string controller_id = get_controller_id(ob_arm, ob); openSkin(controller_id, controller_name, COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob))); add_bind_shape_mat(ob); std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id); std::string weights_source_id = add_weights_source(me, controller_id); add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase); closeSkin(); closeController(); }
//--------------------------------------------------------------- void ControllerExporter::exportSkinController( ExportNode* exportNode, SkinController* skinController, const String& controllerId, const String& skinSource ) { INode* iNode = exportNode->getINode(); if ( !skinController ) return; // We cannot use skin->GetContextInterface to get ISkinContextData if we are exporting an XRef, since we cannot access // the INode the object belongs to in the referenced file. To solve this problem, we temporarily create an INode, that references // the object and delete it immediately. ISkinInterface* skinInterface = getISkinInterface( exportNode, skinController ); if ( !skinInterface ) return; openSkin(controllerId, skinSource); Matrix3 bindShapeTransformationMatrix; skinInterface->getSkinInitTM(bindShapeTransformationMatrix, true); double bindShapeTransformationArray[4][4]; VisualSceneExporter::matrix3ToDouble4x4(bindShapeTransformationArray, bindShapeTransformationMatrix); addBindShapeTransform(bindShapeTransformationArray); int jointCount = skinInterface->getNumBones(); INodeList boneINodes; // Export joints source String jointsId = controllerId + JOINTS_SOURCE_ID_SUFFIX; COLLADASW::NameSource jointSource(mSW); jointSource.setId(jointsId); jointSource.setArrayId(jointsId + ARRAY_ID_SUFFIX); jointSource.setAccessorStride(1); jointSource.getParameterNameList().push_back("JOINT"); jointSource.setAccessorCount(jointCount); jointSource.prepareToAppendValues(); for (int i = 0; i < jointCount; ++i) { // there should not be any null bone. // the ISkin::GetBone, not GetBoneFlat, function is called here. INode* boneNode = skinInterface->getBone(i); assert(boneNode); boneINodes.push_back(boneNode); ExportNode* jointExportNode = mExportSceneGraph->getExportNode(boneNode); assert(jointExportNode); if ( !jointExportNode->hasSid() ) jointExportNode->setSid(mExportSceneGraph->createJointSid()); jointExportNode->setIsJoint(); jointSource.appendValues(jointExportNode->getSid()); } jointSource.finish(); determineReferencedJoints(exportNode, skinController); //export inverse bind matrix source String inverseBindMatrixId = controllerId + BIND_POSES_SOURCE_ID_SUFFIX; COLLADASW::Float4x4Source inverseBindMatrixSource(mSW); inverseBindMatrixSource.setId(inverseBindMatrixId); inverseBindMatrixSource.setArrayId(inverseBindMatrixId + ARRAY_ID_SUFFIX); inverseBindMatrixSource.setAccessorStride(16); inverseBindMatrixSource.getParameterNameList().push_back("TRANSFORM"); inverseBindMatrixSource.setAccessorCount(jointCount); inverseBindMatrixSource.prepareToAppendValues(); for (int i = 0; i < jointCount; ++i) { INode* boneNode = boneINodes[i]; Matrix3 bindPose; if ( !skinInterface->getBoneInitTM(boneNode, bindPose) ) { bindPose = VisualSceneExporter::getWorldTransform( boneNode, mDocumentExporter->getOptions().getAnimationStart() ); } bindPose.Invert(); double bindPoseArray[4][4]; VisualSceneExporter::matrix3ToDouble4x4(bindPoseArray, bindPose); inverseBindMatrixSource.appendValues(bindPoseArray); } inverseBindMatrixSource.finish(); int vertexCount = skinInterface->getNumVertices(); //count weights, excluding the ones equals one int weightsCount = 1; for (int i = 0; i < vertexCount; ++i) { int jointCount = skinInterface->getNumAssignedBones(i); for (int p = 0; p < jointCount; ++p) { float weight = skinInterface->getBoneWeight(i, p); if ( !COLLADASW::MathUtils::equals(weight, 1.0f) ) weightsCount++; } } //export weights source String weightsId = controllerId + WEIGHTS_SOURCE_ID_SUFFIX; COLLADASW::FloatSource weightsSource(mSW); weightsSource.setId(weightsId); weightsSource.setArrayId(weightsId + ARRAY_ID_SUFFIX); weightsSource.setAccessorStride(1); weightsSource.getParameterNameList().push_back("WEIGHT"); weightsSource.setAccessorCount(weightsCount); weightsSource.prepareToAppendValues(); weightsSource.appendValues(1.0); for (int i = 0; i < vertexCount; ++i) { int jointCount = skinInterface->getNumAssignedBones(i); for (int p = 0; p < jointCount; ++p) { float weight = skinInterface->getBoneWeight(i, p); if ( !COLLADASW::MathUtils::equals(weight, 1.0f) ) weightsSource.appendValues(weight); } } weightsSource.finish(); COLLADASW::JointsElement joints(mSW); joints.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, "#" + jointsId)); joints.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX, "#" + inverseBindMatrixId)); joints.add(); COLLADASW::VertexWeightsElement vertexWeights(mSW); COLLADASW::Input weightInput(COLLADASW::InputSemantic::WEIGHT, "#" + weightsId); vertexWeights.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, "#" + jointsId, 0)); vertexWeights.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT, "#" + weightsId, 1)); vertexWeights.setCount(vertexCount); vertexWeights.prepareToAppendVCountValues(); for (int i = 0; i < vertexCount; ++i) vertexWeights.appendValues(skinInterface->getNumAssignedBones(i)); vertexWeights.CloseVCountAndOpenVElement(); int currentIndex = 1; for (int i = 0; i < vertexCount; ++i) { int jointCount = skinInterface->getNumAssignedBones(i); for (int p = 0; p < jointCount; ++p) { vertexWeights.appendValues(skinInterface->getAssignedBone(i, p)); float weight = skinInterface->getBoneWeight(i, p); if ( !COLLADASW::MathUtils::equals(weight, 1.0f) ) { vertexWeights.appendValues(currentIndex++); } else { vertexWeights.appendValues(0); } } } vertexWeights.finish(); closeSkin(); skinInterface->releaseMe(); }