/* * Copyright 2006 Sony Computer Entertainment Inc. * * Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at: * http://research.scea.com/scea_shared_source_license.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing permissions and limitations under the * License. */ #include "daeReader.h" #include #include #include #include #include #include #include #include #include using namespace osgDAE; domNode* daeReader::getRootJoint(domNode* joint) const { int depth = 0; while (domNode* parent = daeSafeCast(joint->getParent())) { if (isJoint(parent)) { joint = parent; ++depth; } else { break; } } return joint; } domNode* daeReader::findJointNode(daeElement* searchFrom, domInstance_controller* pDomInstanceController) const { domController *pDomController = daeSafeCast(getElementFromURI(pDomInstanceController->getUrl())); domSkin::domJoints* pDomSkinJoints = pDomController->getSkin()->getJoints(); domInputLocal_Array domInputs = pDomSkinJoints->getInput_array(); domSource* pDomJointsSource = NULL; for (size_t i=0; i < domInputs.getCount(); i++) { if (!strcmp(domInputs[i]->getSemantic(), COMMON_PROFILE_INPUT_JOINT)) { pDomJointsSource = daeSafeCast(getElementFromURI(domInputs[i]->getSource())); if (!pDomJointsSource) { osg::notify( osg::WARN ) << "Could not find skin joints source '" << domInputs[i]->getSource().getURI() << "'" <getIDREF_array()) { if (pDomIDREFs->getCount()) { return daeSafeCast< domNode >(getElementFromIDRef(pDomIDREFs->getValue().get(0))); } } else if (domName_array* pDomNames = pDomJointsSource->getName_array()) { if (pDomNames->getCount()) { daeString target = pDomNames->getValue().get(0); daeSIDResolver resolver(searchFrom, target); return daeSafeCast(resolver.getElement()); } } osg::notify( osg::WARN ) << "No valid names or IDREFS array in " < SkelSkinMap; SkelSkinMap skelSkinMap; //group the skins according to which group of joints they're attached to. for (size_t i = 0; i < _skinInstanceControllers.size(); ++i) { domInstance_controller* pDomInstanceController = _skinInstanceControllers[i]; const domInstance_controller::domSkeleton_Array& pDomSkeletons = pDomInstanceController->getSkeleton_array(); if (pDomSkeletons.getCount() == 0) { domNode* skelNode = findSkeletonNode(_skeletonMap.begin()->first, pDomInstanceController); if (skelNode) { skelSkinMap[skelNode].push_back(pDomInstanceController); } } else { if (daeElement* pDaeElement = pDomSkeletons.get(0)->getValue().getElement()) { if (domNode* skelNode = findSkeletonNode(pDaeElement, pDomInstanceController)) { skelSkinMap[skelNode].push_back(pDomInstanceController); } } } } for (SkelSkinMap::iterator it = skelSkinMap.begin(); it != skelSkinMap.end(); ++it) { processSkeletonSkins(it->first, it->second); } } void getJointsAndInverseObjectspaceBindMatrices(domInstance_controller* pDomInstanceController, domNode* pDomSkeletonNode, std::vector >& jointsAndBindMatrices) { domController* pDomController = daeSafeCast< domController >(getElementFromURI(pDomInstanceController->getUrl())); domSkin* pDomSkin = pDomController->getSkin(); domSkin::domJoints* pDomSkinJoints = pDomSkin->getJoints(); domInputLocal_Array domInputs = pDomSkinJoints->getInput_array(); if (domInputs.getCount() > 2) { osg::notify( osg::WARN ) << "Only a single pair of skin joints inputs is supported." << std::endl; } domSource* pDomJointsSource = NULL; domSource* pDomInvBindMatricesSource = NULL; for (size_t i=0; i < domInputs.getCount(); i++) { if (!strcmp(domInputs[i]->getSemantic(), COMMON_PROFILE_INPUT_JOINT)) { pDomJointsSource = daeSafeCast(getElementFromURI(domInputs[i]->getSource())); if (!pDomJointsSource) { osg::notify( osg::WARN ) << "Could not find skin joints source '" << domInputs[i]->getSource().getURI() << "'" <getSemantic(), COMMON_PROFILE_INPUT_INV_BIND_MATRIX)) { pDomInvBindMatricesSource = daeSafeCast(getElementFromURI(domInputs[i]->getSource())); if (!pDomInvBindMatricesSource) { osg::notify( osg::WARN ) << "Could not find skin inverse bind matrices source '" << domInputs[i]->getSource().getURI() << "'" <getFloat_array(); domListOfFloats matrices = pDomFloatArray->getValue(); osg::Matrix parentInverseSkeletonBindMatrix; if (domIDREF_array* pDomIDREFs = pDomJointsSource->getIDREF_array()) { // IDREFS refer to an absolute joint and therefore do not allow a different skeleton xsIDREFS* pIDREFS = &(pDomIDREFs->getValue()); for (size_t i=0; i < pIDREFS->getCount(); i++) { domNode* pDomNode = daeSafeCast< domNode >(getElementFromIDRef(pIDREFS->get(i))); if (pDomNode) { jointsAndBindMatrices.push_back(std::pair(pDomNode, osg::Matrix())); } else { osg::notify( osg::WARN ) << "Failed to locate joint '" << pIDREFS->get(i).getID() << "'" << std::endl; } } } else if (domName_array* pDomNames = pDomJointsSource->getName_array()) { // Using a list of names is the preferred way of referring to joints, because // this refers to a joint relative to the given skeletons domListOfNames* pNames = &(pDomNames->getValue()); for (size_t i=0; i < pNames->getCount(); i++) { daeSIDResolver resolver(pDomSkeletonNode, pNames->get(i)); domNode* pDomNode = daeSafeCast< domNode >(resolver.getElement()); if (pDomNode) { jointsAndBindMatrices.push_back(std::pair(pDomNode, osg::Matrix())); } else { osg::notify( osg::WARN ) << "Failed to locate joint '" << pNames->get(i) << "'" << std::endl; } } } else { osg::notify( osg::WARN ) << "No valid names or IDREFS array in " < > jointsAndInverseBindMatrices; getJointsAndInverseObjectspaceBindMatrices(instanceController, skeletonRoot, jointsAndInverseBindMatrices); for (size_t j = 0; j < jointsAndInverseBindMatrices.size(); ++j) { osgAnimation::Bone* pOsgBone = getOrCreateBone(jointsAndInverseBindMatrices[j].first); pOsgBone->setInvBindMatrixInSkeletonSpace(jointsAndInverseBindMatrices[j].second); } } osgAnimation::Skeleton* skeleton = getOrCreateSkeleton(skeletonRoot); for (size_t i = 0; i < instanceControllers.size(); ++i) { domInstance_controller *pDomInstanceController = instanceControllers[i]; domController *pDomController = daeSafeCast< domController >(getElementFromURI(pDomInstanceController->getUrl())); processSkin(pDomController->getSkin(), skeletonRoot, skeleton, pDomInstanceController->getBind_material()); } } osgAnimation::VertexInfluence& getVertexInfluence( osgAnimation::VertexInfluenceMap& vim, const std::string& name) { osgAnimation::VertexInfluenceMap::iterator it = vim.lower_bound(name); if (it == vim.end() || name != it->first) { it = vim.insert(it, osgAnimation::VertexInfluenceMap::value_type( name, osgAnimation::VertexInfluence())); it->second.setName(name); } return it->second; } // // 0..1 // 3..* // 1 // 2..* // 0..* // 1 // 2..* // 0..1 // 0..1 // 0.* // 0..* void daeReader::processSkin(domSkin* pDomSkin, domNode* skeletonRoot, osgAnimation::Skeleton* pOsgSkeleton, domBind_material* pDomBindMaterial) { daeElement* pDaeSkinSource = getElementFromURI( pDomSkin->getSource()); if (!pDaeSkinSource) { osg::notify( osg::WARN ) << "Failed to locate geometry " << pDomSkin->getSource().getURI() << std::endl; return; } domGeometry* pDomGeometry = daeSafeCast< domGeometry >(pDaeSkinSource); if (!pDomGeometry) { osg::notify( osg::WARN ) << "Skin source is of type " << pDaeSkinSource->getTypeName() << " which is not supported." << std::endl; return; } // Base mesh const osg::Geode* pOriginalGeode = NULL; osg::Geode* pOsgGeode = getOrCreateGeometry(pDomGeometry, pDomBindMaterial, &pOriginalGeode); if (!pOsgGeode) return; domMesh* pDomMesh = pDomGeometry->getMesh(); osg::Geode* pOsgRigGeode = new osg::Geode; pOsgRigGeode->setDataVariance(osg::Object::DYNAMIC); typedef std::map GeometryRigGeometryMap; GeometryRigGeometryMap old2newGeometryMap; for (unsigned i = 0; i < pOsgGeode->getNumDrawables(); ++i) { if (osg::Geometry* pOsgGeometry = dynamic_cast(pOsgGeode->getDrawable(i))) { const osg::Geometry* pOriginalGeometry = dynamic_cast(pOriginalGeode->getDrawable(i)); osgAnimation::RigGeometry* pOsgRigGeometry = new osgAnimation::RigGeometry(); pOsgRigGeometry->setSourceGeometry(pOsgGeometry); pOsgRigGeometry->copyFrom(*pOsgGeometry); old2newGeometryMap.insert(GeometryRigGeometryMap::value_type(pOriginalGeometry, pOsgRigGeometry)); pOsgRigGeometry->setDataVariance(osg::Object::DYNAMIC); pOsgRigGeometry->setUseDisplayList( false ); pOsgRigGeode->addDrawable(pOsgRigGeometry); } else { pOsgRigGeode->addDrawable(pOsgGeode->getDrawable(i)); } } pOsgSkeleton->addChild(pOsgRigGeode); // if (domSkin::domBind_shape_matrix* pDomBindShapeMatrix = pDomSkin->getBind_shape_matrix()) { domFloat4x4 matrix = pDomBindShapeMatrix->getValue(); osg::Matrix bindMatrix( matrix.get(0), matrix.get(4), matrix.get(8), matrix.get(12), matrix.get(1), matrix.get(5), matrix.get(9), matrix.get(13), matrix.get(2), matrix.get(6), matrix.get(10), matrix.get(14), matrix.get(3), matrix.get(7), matrix.get(11), matrix.get(15)); for (unsigned d = 0; d < pOsgRigGeode->getNumDrawables(); ++d) { osgAnimation::RigGeometry* pOsgRigGeometry = dynamic_cast(pOsgRigGeode->getDrawable(d)); if (!pOsgRigGeometry) continue; osg::Vec3Array& vertices = *static_cast(pOsgRigGeometry->getVertexArray()); for (size_t i = 0; i < vertices.size(); ++i) { vertices[i] = vertices[i] * bindMatrix; } if (osg::Vec3Array* normals = static_cast(pOsgRigGeometry->getNormalArray())) { for (size_t i = 0; i < normals->size(); ++i) { (*normals)[i] = osg::Matrix::transform3x3((*normals)[i], bindMatrix); } } } } // 1 domSkin::domVertex_weights* pDomVertexWeights = pDomSkin->getVertex_weights(); domInputLocalOffset_Array domInputs = pDomVertexWeights->getInput_array(); if (domInputs.getCount() > 2) { osg::notify( osg::WARN ) << "Only a single pair of skin vertex weights inputs is supported." << std::endl; } domSource* pDomJointsSource = NULL; domSource* pDomWeightsSource = NULL; for (size_t i=0; i < 2; i++) { if (!strcmp(domInputs[i]->getSemantic(), COMMON_PROFILE_INPUT_JOINT)) { pDomJointsSource = daeSafeCast(getElementFromURI(domInputs[i]->getSource())); if (!pDomJointsSource) { osg::notify( osg::WARN ) << "Could not find skin joints source '" << domInputs[i]->getSource().getURI() << "'" <getSemantic(), COMMON_PROFILE_INPUT_WEIGHT)) { pDomWeightsSource = daeSafeCast(getElementFromURI(domInputs[i]->getSource())); if (!pDomWeightsSource) { osg::notify( osg::WARN ) << "Could not find skin weights source '" << domInputs[i]->getSource().getURI() << "'" <getFloat_array(); domListOfFloats weights = pDomFloatArray->getValue(); domSkin::domVertex_weights::domVcount* pDomVcount = pDomVertexWeights->getVcount(); domListOfUInts influenceCounts = pDomVcount->getValue(); domSkin::domVertex_weights::domV* pDomV= pDomVertexWeights->getV(); domListOfInts jointWeightIndices = pDomV->getValue(); std::vector jointNames; if (domName_array* pDomNames = pDomJointsSource->getName_array()) { domListOfNames* pNames = &(pDomNames->getValue()); jointNames.reserve(pNames->getCount()); for (size_t i = 0; i < pNames->getCount(); ++i) { const char* szName = pNames->get(i); daeSIDResolver resolver(skeletonRoot, szName); osgAnimation::Bone* pOsgBone = _jointMap[daeSafeCast(resolver.getElement())].get(); if (pOsgBone) { jointNames.push_back(pOsgBone->getName()); } else { jointNames.push_back(szName); osg::notify(osg::WARN) << "Cannot find bone " << szName << std::endl; } } } else if (domIDREF_array* pDomIDREFs = pDomJointsSource->getIDREF_array()) { xsIDREFS* pIDREFs = &(pDomIDREFs->getValue()); jointNames.reserve(pIDREFs->getCount()); for (size_t i = 0; i < pIDREFs->getCount(); ++i) { osgAnimation::Bone* pOsgBone = _jointMap[daeSafeCast(pIDREFs->get(i).getElement())].get(); if (pOsgBone) { jointNames.push_back(pOsgBone->getName()); } else { jointNames.push_back(pIDREFs->get(i).getID()); osg::notify(osg::WARN) << "Cannot find bone " << pIDREFs->get(i).getID() << std::endl; } } } else { osg::notify( osg::WARN ) << "No valid names or IDREFS array in " < jointWeightIndices.getCount()) { osg::notify( osg::WARN ) << "vIndex is larger than number of v values" <= jointNames.size()) { osg::notify( osg::WARN ) << "Joint index is larger the number of joints" <= weights.getCount()) { osg::notify( osg::WARN ) << "Weight index is larger the number of weights" < 0.0f) { const std::string& name = jointNames[jointIndex]; for (OldToNewIndexMap::const_iterator it = start; it != end; ++it) { osgAnimation::RigGeometry* pRigGeometry = old2newGeometryMap[it->second.first.get()]; osgAnimation::VertexInfluenceMap* vim = pRigGeometry->getInfluenceMap(); if (!vim) { pRigGeometry->setInfluenceMap(vim = new osgAnimation::VertexInfluenceMap); } getVertexInfluence(*vim, name).push_back( osgAnimation::VertexIndexWeight(it->second.second, weight)); } } } } }