void ControllerExporter::determineReferencedJoints(ExportNode* exportNode, SkinController* skinController) { ISkinInterface* skinInterface = getISkinInterface( exportNode, skinController); int jointCount = skinInterface->getNumBones(); ExportNodeSet referencedJoints; 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); ExportNode* jointExportNode = mExportSceneGraph->getExportNode(boneNode); assert(jointExportNode); jointExportNode->setIsInVisualScene( true ); referencedJoints.insert(jointExportNode); } determineSkeletonRoots(referencedJoints, exportNode->getControllerList()); skinInterface->releaseMe(); }
//--------------------------------------------------------------- ExportNode * ExportSceneGraph::create ( INode *iNode, ExportNode* parent, bool& isInVisualScene) { ExportNode * exportNode = new ExportNode ( iNode, parent ); isInVisualScene = isNodeInVisualScene(iNode); int numberOfChildren = iNode->NumberOfChildren(); for ( int i = 0; i < numberOfChildren; ++i ) { INode * child = iNode->GetChildNode ( i ); bool isChildInVisualScene; ExportNode * childExportNode = create ( child, exportNode, isChildInVisualScene ); exportNode->add( childExportNode ); if ( isChildInVisualScene ) isInVisualScene = true; } exportNode->setId ( mNodeIdList.addId ( NativeString(iNode->GetName()) ) ); mINodeExportNodeMap[iNode] = exportNode; exportNode->createControllerList(); //createBones(exportNode); exportNode->setIsInVisualScene(isInVisualScene); return exportNode; }
//--------------------------------------------------------------- void ExportSceneGraph::findReferencedObjects( ExportNode* exportNode ) { if ( exportNode->hasControllers() ) { ControllerList* controllerList = exportNode->getControllerList(); size_t controllerCount = controllerList->getControllerCount(); for ( size_t j = 0; j < controllerCount; ++j) { Controller* controller = controllerList->getController(j); if ( controller->getType() != Controller::MORPH ) continue; MorphController* morphController = (MorphController*)controller; MorphR3* morpher = morphController->getMorph(); size_t channelBankCount = morpher->chanBank.size(); for ( size_t i = 0; i<channelBankCount; ++i) { morphChannel& channel = morpher->chanBank[i]; if (!channel.mActive || channel.mNumPoints == 0) continue; INode* targetINode = channel.mConnection; if ( !targetINode ) { MorphControllerHelperGeometry morphControllerHelperGeometry; morphControllerHelperGeometry.exportNode = exportNode; morphControllerHelperGeometry.morphController = morphController; morphControllerHelperGeometry.controllerId = ControllerExporter::getControllerId(*exportNode, controllerCount - j, controllerList->getController(j)->getType()); morphControllerHelperGeometry.channelBankindex = i; mMorphControllerHelperGeometryList.push_back(morphControllerHelperGeometry); } else { ExportNode* targetExportNode = getExportNode(targetINode); targetExportNode->setIsReferenced(true); } } } } size_t numberOfChildren = exportNode->getNumberOfChildren(); for ( size_t i = 0; i < numberOfChildren; ++i ) findReferencedObjects(exportNode->getChild(i)); }
//--------------------------------------------------------------- String LightExporter::getLightId( const ExportNode& exportNode ) { return exportNode.getId() + LIGHT_ID_SUFFIX; }
//--------------------------------------------------------------- COLLADASW::String GeometriesExporter::getGeometryId( const ExportNode& exportNode ) { return COLLADASW::LibraryGeometries::GEOMETRY_ID_PRAEFIX + exportNode.getId() ; }
//--------------------------------------------------------------- void ControllerExporter::exportMorphController( ExportNode* exportNode, MorphController* morphController, const String& controllerId, const String& morphSource ) { MorphR3* morpher = morphController->getMorph(); FloatList listOfWeights; StringList listOfTargetIds; String weightsId = controllerId + WEIGHTS_SOURCE_ID_SUFFIX; size_t channelBankCount = morpher->chanBank.size(); for ( size_t i = 0; i<channelBankCount; ++i) { morphChannel& channel = morpher->chanBank[i]; if (!channel.mActive || channel.mNumPoints == 0) continue; INode* targetINode = channel.mConnection; listOfWeights.push_back(ConversionFunctors::fromPercent(channel.cblock->GetFloat(morphChannel::cblock_weight_index, mDocumentExporter->getOptions().getAnimationStart()))); Control* weightController = channel.cblock->GetController(morphChannel::cblock_weight_index); mDocumentExporter->getAnimationExporter()->addAnimatedFloat(weightController, weightsId, EMPTY_STRING, (int)i, true, &ConversionFunctors::fromPercent ); if ( !targetINode ) { MorphControllerHelperGeometry morphControllerHelperGeometry; morphControllerHelperGeometry.exportNode = exportNode; morphControllerHelperGeometry.controllerId = controllerId; morphControllerHelperGeometry.morphController = morphController; morphControllerHelperGeometry.channelBankindex = i; String targetId = ExportSceneGraph::getMorphControllerHelperId(morphControllerHelperGeometry); listOfTargetIds.push_back(targetId); } else { ExportNode* targetExportNode = mExportSceneGraph->getExportNode(targetINode); assert(targetExportNode); ExportNode* geometryExportNode = mDocumentExporter->getExportedObjectExportNode(ObjectIdentifier(targetExportNode->getInitialPose())); assert( geometryExportNode ); // listOfTargetIds.push_back(geometryExportNode); listOfTargetIds.push_back(GeometriesExporter::getGeometryId(*geometryExportNode)); } } openMorph(controllerId, EMPTY_STRING, morphSource); //export weights source String targetId = controllerId + TARGETS_SOURCE_ID_SUFFIX; COLLADASW::IdRefSource targetsSource(mSW); targetsSource.setId(targetId); targetsSource.setArrayId(targetId + ARRAY_ID_SUFFIX); targetsSource.setAccessorStride(1); targetsSource.getParameterNameList().push_back("MORPH_TARGET"); targetsSource.setAccessorCount((unsigned long)listOfTargetIds.size()); targetsSource.prepareToAppendValues(); for ( StringList::const_iterator it = listOfTargetIds.begin(); it != listOfTargetIds.end(); ++it) targetsSource.appendValues(*it); targetsSource.finish(); //export weights source COLLADASW::FloatSource weightsSource(mSW); weightsSource.setId(weightsId); weightsSource.setArrayId(weightsId + ARRAY_ID_SUFFIX); weightsSource.setAccessorStride(1); weightsSource.getParameterNameList().push_back("MORPH_WEIGHT"); weightsSource.setAccessorCount((unsigned long)listOfWeights.size()); weightsSource.prepareToAppendValues(); for ( FloatList::const_iterator it = listOfWeights.begin(); it != listOfWeights.end(); ++it) weightsSource.appendValues(*it); weightsSource.finish(); COLLADASW::TargetsElement targets(mSW); targets.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::MORPH_TARGET, "#" + targetId)); targets.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::MORPH_WEIGHT, "#" + weightsId)); targets.add(); closeMorph(); }
//--------------------------------------------------------------- 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(); }
//--------------------------------------------------------------- void ControllerList::resolveControllers( const ExportNode& exportNode ) { Object* object = exportNode.getINode()->GetObjectRef(); if ( !object ) return; if ( exportNode.getIsXRefObject() ) object = XRefFunctions::getXRefItemSource(object); if ( !object ) return; SClass_ID superClassId; IDerivedObject* derivedObject; Object *currentObject = object; //int modIdx = 0; superClassId = object->SuperClassID(); if (superClassId == GEN_DERIVOB_CLASS_ID || superClassId == DERIVOB_CLASS_ID || superClassId == WSM_DERIVOB_CLASS_ID) { derivedObject = (IDerivedObject*)object; while (superClassId == GEN_DERIVOB_CLASS_ID || superClassId == DERIVOB_CLASS_ID || superClassId == WSM_DERIVOB_CLASS_ID) { for (int modifierIndex = 0; modifierIndex < derivedObject->NumModifiers(); ++modifierIndex) { Modifier* modifier = derivedObject->GetModifier(modifierIndex); //no iskin support for xrefs // TODO needs further investigation... if ( SkinController::isSkinController(modifier) /*&& !exportNode.getIsXRefObject() */) { SkinController * skinController = new SkinController(derivedObject, modifierIndex, modifier->IsEnabled() != false); mControllers.push_back(skinController); } else if ( MorphController::isMorphController(modifier) ) { MorphController * morphController = new MorphController(derivedObject, modifierIndex, modifier->IsEnabled() != false); mControllers.push_back(morphController); } else return; } derivedObject = (IDerivedObject*) derivedObject->GetObjRef(); currentObject = (Object*) derivedObject; superClassId = derivedObject->SuperClassID(); } } /* int bct = currentObject->NumPipeBranches(FALSE); if (bct > 0) { for (int bi = 0; bi < bct; bi++) { Object* bobj = currentObject->GetPipeBranch(bi,FALSE); Resolve(bobj); return; } } */ }
//--------------------------------------------------------------- String CameraExporter::getCameraId( const ExportNode& exportNode ) { return exportNode.getId() + CAMERA_ID_SUFFIX; }
//--------------------------------------------------------------- void CameraExporter::exportCamera( ExportNode* exportNode ) { if ( !exportNode->getIsInVisualScene() ) return; String cameraId = getCameraId(*exportNode); INode* iNode = exportNode->getINode(); CameraObject* camera = (CameraObject*)iNode->GetObjectRef(); INode* targetNode = ( camera->ClassID().PartA() == LOOKAT_CAM_CLASS_ID) ? iNode->GetTarget() : 0; if ( camera ) { if ( mDocumentExporter->isExportedObject(ObjectIdentifier(camera)) ) return; mDocumentExporter->insertExportedObject(ObjectIdentifier(camera), exportNode); // Retrieve the camera parameters block IParamBlock* parameters = (IParamBlock*) camera->GetReference(MaxCamera::PBLOCK_REF); COLLADASW::BaseOptic * optics = 0; if ( camera->IsOrtho() ) { optics = new COLLADASW::OrthographicOptic(COLLADASW::LibraryCameras::mSW); // Calculate the target distance for FOV calculations float targetDistance; if ( targetNode ) { Point3 targetTrans = targetNode->GetNodeTM(mDocumentExporter->getOptions().getAnimationStart()).GetTrans(); Point3 cameraTrans = iNode->GetNodeTM(mDocumentExporter->getOptions().getAnimationStart()).GetTrans(); targetDistance = (targetTrans - cameraTrans).Length(); } else { targetDistance = camera->GetTDist(mDocumentExporter->getOptions().getAnimationStart()); } ConversionInverseOrthoFOVFunctor conversionInverseOrthoFOVFunctor(targetDistance); if ( AnimationExporter::isAnimated(parameters, MaxCamera::FOV) ) { optics->setXMag(conversionInverseOrthoFOVFunctor(parameters->GetFloat(MaxCamera::FOV)), XMAG_SID); mAnimationExporter->addAnimatedParameter(parameters, MaxCamera::FOV, cameraId, XMAG_SID, 0, true, &conversionInverseOrthoFOVFunctor); } else { optics->setXMag(conversionInverseOrthoFOVFunctor(parameters->GetFloat(MaxCamera::FOV))); } } else { optics = new COLLADASW::PerspectiveOptic(COLLADASW::LibraryCameras::mSW); if ( AnimationExporter::isAnimated(parameters, MaxCamera::FOV) ) { optics->setXFov(COLLADASW::MathUtils::radToDegF(parameters->GetFloat(MaxCamera::FOV)), XFOV_SID); mAnimationExporter->addAnimatedParameter(parameters, MaxCamera::FOV, cameraId, XFOV_SID, 0, true, &ConversionFunctors::radToDeg); } else { optics->setXFov(COLLADASW::MathUtils::radToDegF(parameters->GetFloat(MaxCamera::FOV))); } } bool hasAnimatedZNear = mAnimationExporter->addAnimatedParameter(parameters, MaxCamera::NEAR_CLIP, cameraId, optics->getZNearDefaultSid(), 0); optics->setZNear(parameters->GetFloat(MaxCamera::NEAR_CLIP), hasAnimatedZNear); bool hasAnimatedZFar = mAnimationExporter->addAnimatedParameter(parameters, MaxCamera::FAR_CLIP, cameraId, optics->getZFarDefaultSid(), 0); optics->setZFar(parameters->GetFloat(MaxCamera::FAR_CLIP), hasAnimatedZFar); #ifdef UNICODE String exportNodeName = COLLADABU::StringUtils::wideString2utf8String(exportNode->getINode()->GetName()); COLLADASW::Camera colladaCamera(COLLADASW::LibraryCameras::mSW, optics, cameraId, COLLADASW::Utils::checkNCName(exportNodeName)); #else COLLADASW::Camera colladaCamera(COLLADASW::LibraryCameras::mSW, optics, cameraId, COLLADASW::Utils::checkNCName(exportNode->getINode()->GetName())); #endif setExtraTechnique(&colladaCamera); // Retrieve the camera target if ( targetNode ) { ExportNode* targetExportNode = mExportSceneGraph->getExportNode(targetNode); addExtraParameter(EXTRA_PARAMETER_TARGET, "#" + targetExportNode->getId()); } if (camera->GetMultiPassEffectEnabled(0, FOREVER)) { IMultiPassCameraEffect *multiPassCameraEffect = camera->GetIMultiPassCameraEffect(); if (multiPassCameraEffect) { Class_ID id = multiPassCameraEffect->ClassID(); // the camera could have both effects, but not in Max if (id == FMULTI_PASS_MOTION_BLUR_CLASS_ID) { IParamBlock2 *parameters = multiPassCameraEffect->GetParamBlock(0); if (parameters ) { addParamBlockAnimatedExtraParameters(MOTION_BLUR_ELEMENT, MOTION_BLUR_PARAMETERS, MOTION_BLUR_PARAMETER_COUNT, parameters, cameraId); } } else if (id == FMULTI_PASS_DOF_CLASS_ID) { IParamBlock2 *parameters = multiPassCameraEffect->GetParamBlock(0); if (parameters ) { addParamBlockAnimatedExtraParameters(DEPTH_OF_FIELD_ELEMENT, DEPTH_OF_FIELD_PARAMETERS, DEPTH_OF_FIELD_PARAMETER_COUNT, parameters, cameraId); addExtraParameter(TARGETDISTANCE_PARAMETER, camera->GetTDist(0)); } } } } addCamera(colladaCamera); delete optics; } }