//-------------------------------------------------------------------------- bool VertexAnimationTrack::getVertexAnimationIncludesNormals() const { if (mAnimationType == VAT_NONE) return false; if (mAnimationType == VAT_MORPH) { bool normals = false; for (KeyFrameList::const_iterator i = mKeyFrames.begin(); i != mKeyFrames.end(); ++i) { VertexMorphKeyFrame* kf = static_cast<VertexMorphKeyFrame*>(*i); bool thisnorm = kf->getVertexBuffer()->getVertexSize() > 12; if (i == mKeyFrames.begin()) normals = thisnorm; else // Only support normals if ALL keyframes include them normals = normals && thisnorm; } return normals; } else { // needs to derive from Mesh::PoseList, can't tell here return false; } }
//--------------------------------------------------------------------- void PlayPen_testMorphAnimationWithoutNormals::setupContent() { bool testStencil = false; if (testStencil) mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE); mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5)); Vector3 dir(-1, -1, 0.5); dir.normalise(); Light* l = mSceneMgr->createLight("light1"); l->setType(Light::LT_DIRECTIONAL); l->setDirection(dir); MeshPtr mesh = MeshManager::getSingleton().load("sphere.mesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); String morphName = "testmorphnonormals.mesh"; mesh = mesh->clone(morphName); SubMesh* sm = mesh->getSubMesh(0); // Re-organise geometry since this mesh has no animation and all // vertex elements are packed into one buffer VertexDeclaration* newDecl = sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(false, true, false); sm->vertexData->reorganiseBuffers(newDecl); if (testStencil) sm->vertexData->prepareForShadowVolume(); // need to re-prep since reorganised // get the position buffer (which should now be separate); const VertexElement* posElem = sm->vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); HardwareVertexBufferSharedPtr origbuf = sm->vertexData->vertexBufferBinding->getBuffer( posElem->getSource()); // Create a new position & normal buffer with updated values HardwareVertexBufferSharedPtr newbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_FLOAT3), sm->vertexData->vertexCount, HardwareBuffer::HBU_STATIC, true); float* pSrc = static_cast<float*>(origbuf->lock(HardwareBuffer::HBL_READ_ONLY)); float* pDst = static_cast<float*>(newbuf->lock(HardwareBuffer::HBL_DISCARD)); // Make the sphere turn into a cube // Do this just by clamping each of the directions (we shrink it) float cubeDimension = 0.3f * mesh->getBoundingSphereRadius(); for (size_t v = 0; v < sm->vertexData->vertexCount; ++v) { // x/y/z position Vector3 pos; for (int d = 0; d < 3; ++d) { if (*pSrc >= 0) { pos.ptr()[d] = std::min(cubeDimension, *pSrc++); } else { pos.ptr()[d] = std::max(-cubeDimension, *pSrc++); } *pDst++ = pos.ptr()[d]; } } origbuf->unlock(); newbuf->unlock(); // create a morph animation Animation* anim = mesh->createAnimation("testAnim", 10.0f); VertexAnimationTrack* vt = anim->createVertexTrack(1, sm->vertexData, VAT_MORPH); // re-use start positions for frame 0 VertexMorphKeyFrame* kf = vt->createVertexMorphKeyFrame(0); kf->setVertexBuffer(origbuf); // Use translated buffer for mid frame kf = vt->createVertexMorphKeyFrame(4.0f); kf->setVertexBuffer(newbuf); // Pause there kf = vt->createVertexMorphKeyFrame(6.0f); kf->setVertexBuffer(newbuf); // re-use start positions for final frame kf = vt->createVertexMorphKeyFrame(10.0f); kf->setVertexBuffer(origbuf); // Export the mesh DataStreamPtr stream = Root::getSingleton().createFileStream(morphName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); MeshSerializer ser; ser.exportMesh(mesh.get(), stream); stream->close(); // Unload old mesh to force reload MeshManager::getSingleton().remove(mesh->getHandle()); mesh->unload(); mesh.setNull(); Entity* e = mSceneMgr->createEntity("test", morphName); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e); AnimationState* animState = e->getAnimationState("testAnim"); animState->setEnabled(true); animState->setWeight(1.0f); mAnimStateList.push_back(animState); e = mSceneMgr->createEntity("test2", morphName); mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200,0,0))->attachObject(e); // test hardware morph e->setMaterialName("Examples/HardwareMorphAnimation"); animState = e->getAnimationState("testAnim"); animState->setEnabled(true); animState->setWeight(1.0f); mAnimStateList.push_back(animState); mCamera->setNearClipDistance(0.5); mCamera->setPosition(0,100,-400); mCamera->lookAt(Vector3::ZERO); //mSceneMgr->setShowDebugShadows(true); Plane plane; plane.normal = Vector3::UNIT_Y; plane.d = 200; MeshManager::getSingleton().createPlane("Myplane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z); Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" ); pPlaneEnt->setMaterialName("2 - Default"); pPlaneEnt->setCastShadows(false); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt); }
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; }