//----------------------------------------------------------------------- void Animation::_applyBaseKeyFrame() { if (mUseBaseKeyFrame) { Animation* baseAnim = this; if (mBaseKeyFrameAnimationName != StringUtil::BLANK && mContainer) baseAnim = mContainer->getAnimation(mBaseKeyFrameAnimationName); if (baseAnim) { for (NodeTrackList::iterator i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i) { NodeAnimationTrack* track = i->second; NodeAnimationTrack* baseTrack; if (baseAnim == this) baseTrack = track; else baseTrack = baseAnim->getNodeTrack(track->getHandle()); TransformKeyFrame kf(baseTrack, mBaseKeyFrameTime); baseTrack->getInterpolatedKeyFrame(baseAnim->_getTimeIndex(mBaseKeyFrameTime), &kf); track->_applyBaseKeyFrame(&kf); } for (VertexTrackList::iterator i = mVertexTrackList.begin(); i != mVertexTrackList.end(); ++i) { VertexAnimationTrack* track = i->second; if (track->getAnimationType() == VAT_POSE) { VertexAnimationTrack* baseTrack; if (baseAnim == this) baseTrack = track; else baseTrack = baseAnim->getVertexTrack(track->getHandle()); VertexPoseKeyFrame kf(baseTrack, mBaseKeyFrameTime); baseTrack->getInterpolatedKeyFrame(baseAnim->_getTimeIndex(mBaseKeyFrameTime), &kf); track->_applyBaseKeyFrame(&kf); } } } // Re-base has been done, this is a one-way translation mUseBaseKeyFrame = false; } }
//--------------------------------------------------------------------- void Animation::apply(Entity* entity, Real timePos, Real weight, bool software, bool hardware) { // Calculate time index for fast keyframe search TimeIndex timeIndex = _getTimeIndex(timePos); VertexTrackList::iterator i; for (i = mVertexTrackList.begin(); i != mVertexTrackList.end(); ++i) { unsigned short handle = i->first; VertexAnimationTrack* track = i->second; VertexData* swVertexData; VertexData* hwVertexData; VertexData* origVertexData; bool firstAnim = false; if (handle == 0) { // shared vertex data firstAnim = !entity->_getBuffersMarkedForAnimation(); swVertexData = entity->_getSoftwareVertexAnimVertexData(); hwVertexData = entity->_getHardwareVertexAnimVertexData(); origVertexData = entity->getMesh()->sharedVertexData; entity->_markBuffersUsedForAnimation(); } else { // sub entity vertex data (-1) SubEntity* s = entity->getSubEntity(handle - 1); // Skip this track if subentity is not visible if (!s->isVisible()) continue; firstAnim = !s->_getBuffersMarkedForAnimation(); swVertexData = s->_getSoftwareVertexAnimVertexData(); hwVertexData = s->_getHardwareVertexAnimVertexData(); origVertexData = s->getSubMesh()->vertexData; s->_markBuffersUsedForAnimation(); } // Apply to both hardware and software, if requested if (software) { if (firstAnim && track->getAnimationType() == VAT_POSE) { // First time through for a piece of pose animated vertex data // We need to copy the original position values to the temp accumulator const VertexElement* origelem = origVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); const VertexElement* destelem = swVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); HardwareVertexBufferSharedPtr origBuffer = origVertexData->vertexBufferBinding->getBuffer(origelem->getSource()); HardwareVertexBufferSharedPtr destBuffer = swVertexData->vertexBufferBinding->getBuffer(destelem->getSource()); destBuffer->copyData(*origBuffer.get(), 0, 0, destBuffer->getSizeInBytes(), true); } track->setTargetMode(VertexAnimationTrack::TM_SOFTWARE); track->applyToVertexData(swVertexData, timeIndex, weight, &(entity->getMesh()->getPoseList())); } if (hardware) { track->setTargetMode(VertexAnimationTrack::TM_HARDWARE); track->applyToVertexData(hwVertexData, timeIndex, weight, &(entity->getMesh()->getPoseList())); } } }
MeshPtr MeshMergeTool::merge(const Ogre::String& name, const Ogre::String& resourceGroupName) { print("Baking: New Mesh started", V_HIGH); MeshPtr mp = MeshManager::getSingleton().createManual(name, resourceGroupName); if (!mBaseSkeleton.isNull()) { mp->setSkeletonName(mBaseSkeleton->getName()); } AxisAlignedBox totalBounds = AxisAlignedBox(); for (std::vector<Ogre::MeshPtr>::iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { print("Baking: adding submeshes for " + (*it)->getName(), V_HIGH); // insert all submeshes for (Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid) { SubMesh* sub = (*it)->getSubMesh(sid); const String name = findSubmeshName((*it), sid); // create submesh with correct name SubMesh* newsub; if (name.length() == 0) { newsub = mp->createSubMesh(); } else { /// @todo check if a submesh with this name has been created before newsub = mp->createSubMesh(name); } newsub->useSharedVertices = sub->useSharedVertices; // add index newsub->indexData = sub->indexData->clone(); // add geometry if (!newsub->useSharedVertices) { newsub->vertexData = sub->vertexData->clone(); if (!mBaseSkeleton.isNull()) { // build bone assignments SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); newsub->addBoneAssignment(vba); } } } newsub->setMaterialName(sub->getMaterialName()); // Add vertex animations for this submesh Animation *anim = 0; for (unsigned short i = 0; i < (*it)->getNumAnimations(); ++i) { anim = (*it)->getAnimation(i); // get or create the animation for the new mesh Animation *newanim; if (mp->hasAnimation(anim->getName())) { newanim = mp->getAnimation(anim->getName()); } else { newanim = mp->createAnimation(anim->getName(), anim->getLength()); } print("Baking: adding vertex animation " + anim->getName() + " for " + (*it)->getName(), V_HIGH); Animation::VertexTrackIterator vti=anim->getVertexTrackIterator(); while (vti.hasMoreElements()) { VertexAnimationTrack *vt = vti.getNext(); // handle=0 targets the main mesh, handle i (where i>0) targets submesh i-1. // In this case there are only submeshes so index 0 will not be used. unsigned short handle = mp->getNumSubMeshes(); VertexAnimationTrack* newvt = newanim->createVertexTrack( handle, vt->getAssociatedVertexData()->clone(), vt->getAnimationType()); for (int keyFrameIndex = 0; keyFrameIndex < vt->getNumKeyFrames(); ++keyFrameIndex) { switch (vt->getAnimationType()) { case VAT_MORPH: { // copy the keyframe vertex buffer VertexMorphKeyFrame *kf = vt->getVertexMorphKeyFrame(keyFrameIndex); VertexMorphKeyFrame *newkf = newvt->createVertexMorphKeyFrame(kf->getTime()); // This creates a ref to the buffer in the original model // so don't delete it until the export is completed. newkf->setVertexBuffer(kf->getVertexBuffer()); break; } case VAT_POSE: { /// @todo implement pose amination merge break; } case VAT_NONE: default: { break; } } } } } print("Baking: adding submesh '" + name + "' with material " + sub->getMaterialName(), V_HIGH); } // sharedvertices if ((*it)->sharedVertexData) { /// @todo merge with existing sharedVertexData if (!mp->sharedVertexData) { mp->sharedVertexData = (*it)->sharedVertexData->clone(); } if (!mBaseSkeleton.isNull()) { Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); mp->addBoneAssignment(vba); } } } print("Baking: adding bounds for " + (*it)->getName(), V_HIGH); // add bounds totalBounds.merge((*it)->getBounds()); } mp->_setBounds(totalBounds); /// @todo merge submeshes with same material /// @todo add parameters mp->buildEdgeList(); print("Baking: Finished", V_HIGH); reset(); return mp; }
SkeletonPtr MergeSkeleton::bake() { MeshCombiner::getSingleton().log( "Baking: New Skeleton started" ); SkeletonPtr sp = SkeletonManager::getSingleton().create( "mergeSkeleton", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); for( std::vector< Ogre::SkeletonPtr >::iterator it = m_Skeletons.begin(); it != m_Skeletons.end(); ++it ) { if( it == m_Skeletons.begin() ) { MeshCombiner::getSingleton().log( "Baking: using " + (*it)->getName() + " as the base skeleton" ); MeshCombiner::getSingleton().log( "Baking: adding bones" ); Skeleton::BoneIterator bit = (*it)->getBoneIterator(); while( bit.hasMoreElements() ) { Bone* bone = bit.getNext(); Bone* newbone = sp->createBone( bone->getName(), bone->getHandle() ); newbone->setScale( bone->getScale() ); newbone->setOrientation( bone->getOrientation() ); newbone->setPosition( bone->getPosition() ); } MeshCombiner::getSingleton().log( "Baking: building bone hierarchy" ); // bone hierarchy bit = (*it)->getBoneIterator(); while( bit.hasMoreElements() ) { Bone* bone = bit.getNext(); Node* pnode = bone->getParent(); if( pnode != NULL ) { Bone* pbone = static_cast<Bone*>( pnode ); sp->getBone( pbone->getHandle() )->addChild( sp->getBone( bone->getHandle() ) ); } } } MeshCombiner::getSingleton().log( "Baking: adding animations for " + (*it)->getName() ); // insert all animations for (unsigned short a=0; a < (*it)->getNumAnimations(); ++a ) { Animation* anim = (*it)->getAnimation( a ); Animation* newanim = sp->createAnimation( anim->getName(), anim->getLength() ); if( anim->getNumNodeTracks() > 0 ) MeshCombiner::getSingleton().log( "Baking: adding node tracks" ); for( unsigned short na=0; na < anim->getNumNodeTracks(); ++na ) { if( anim->hasNodeTrack( na ) ) { NodeAnimationTrack* nat = anim->getNodeTrack( na ); NodeAnimationTrack* newnat = newanim->createNodeTrack( na ); // all key frames for( unsigned short nf=0; nf < nat->getNumKeyFrames(); ++nf ) { TransformKeyFrame* tkf = nat->getNodeKeyFrame( nf ); TransformKeyFrame* newtkf = newnat->createNodeKeyFrame( tkf->getTime() ); newtkf->setRotation( tkf->getRotation() ); newtkf->setTranslate( tkf->getTranslate() ); newtkf->setScale( tkf->getScale() ); } newnat->setAssociatedNode( sp->getBone( nat->getHandle() ) ); } } if( anim->getNumNumericTracks() > 0 ) MeshCombiner::getSingleton().log( "Baking: adding numeric tracks" ); for( unsigned short na=0; na < anim->getNumNumericTracks(); ++na ) { if( anim->hasNumericTrack( na ) ) { NumericAnimationTrack* nat = anim->getNumericTrack( na ); NumericAnimationTrack* newnat = newanim->createNumericTrack( na ); // all key frames for( unsigned short nf=0; nf < nat->getNumKeyFrames(); ++nf ) { NumericKeyFrame* nkf = nat->getNumericKeyFrame( nf ); NumericKeyFrame* newnkf = newnat->createNumericKeyFrame( nkf->getTime() ); newnkf->setValue( nkf->getValue() ); } } } if( anim->getNumVertexTracks() > 0 ) MeshCombiner::getSingleton().log( "Baking: adding vertex tracks" ); for( unsigned short va=0; va < anim->getNumVertexTracks(); ++va ) { if( anim->hasVertexTrack( va ) ) { VertexAnimationTrack* vat = anim->getVertexTrack( va ); VertexAnimationTrack* newvat = newanim->createVertexTrack( va, vat->getAnimationType() ); // all key frames for( unsigned short nf=0; nf < vat->getNumKeyFrames(); ++nf ) { // all morphs VertexMorphKeyFrame* vmkf = vat->getVertexMorphKeyFrame( nf ); if( vmkf != NULL ) { VertexMorphKeyFrame* newvmkf = newvat->createVertexMorphKeyFrame( vmkf->getTime() ); // @todo vertex buffer copying correct?? HardwareVertexBufferSharedPtr buf = vmkf->getVertexBuffer(); HardwareVertexBufferSharedPtr newbuf = HardwareBufferManager::getSingleton().createVertexBuffer( buf->getVertexSize(), buf->getNumVertices(), buf->getUsage(), buf->hasShadowBuffer() ); newbuf->copyData( *buf.getPointer(), 0, 0, buf->getSizeInBytes() ); } // all poses VertexPoseKeyFrame* vpkf = vat->getVertexPoseKeyFrame( nf ); if( vpkf != NULL ) { VertexPoseKeyFrame* newvpkf = newvat->createVertexPoseKeyFrame( vpkf->getTime() ); VertexPoseKeyFrame::PoseRefIterator pit = vpkf->getPoseReferenceIterator(); while( pit.hasMoreElements() ) { VertexPoseKeyFrame::PoseRef pr = pit.getNext(); newvpkf->addPoseReference( pr.poseIndex, pr.influence ); } } } } } } } return sp; }