今天试图添加多个模型的骨骼动画,出了一些问题,郁闷了一上午之后终于找到了问题所在,下面我们就首先给出Tutorial上的一段代码,看看如何使用骨骼动画,再说说我遇到的问题吧n_n
using System; using System.Drawing; using Math3D; using OgreDotNet; using System.Collections.Generic; namespace OgreDotNetTutorial { public class MoveDemoApplication : ExampleApplication { protected Entity mEntity = null; // The entity of the object we are animating protected SceneNode mNode = null; // The SceneNode of the object we are moving protected AnimationState mAnimationState = null; //The AnimationState the moving object protected float mDistance = 0.0f; //The distance the object has left to travel protected Vector3 mDirection = Vector3.Zero; // The direction the object is moving protected Vector3 mDestination = Vector3.Zero; // The destination the object is moving towards protected LinkedList<Vector3> mWalkList = null; // A doubly linked containing the waypoints protected float mWalkSpeed = 35.0f; // The speed at which the object is moving protected bool mWalking = false; // Whether or not the object is moving protected override void CreateScene() { //temporary entity and SceneNode Entity ent; SceneNode node; // Set the default lighting and background color mSceneManager.SetAmbientLight(Color.White); mViewport.SetBackgroundColour(Color.Black); // Create the Robot entity mEntity = mSceneManager.CreateEntity("Robot", "robot.mesh"); // Create the Robot's SceneNode mNode = mSceneManager.GetRootSceneNode().CreateChildSceneNode("RobotNode", new Vector3(0.0f, 0.0f, 25.0f)); mNode.AttachObject(mEntity); // Create the walking list mWalkList = new LinkedList<Vector3>(); mWalkList.AddLast(new Vector3(550.0f, 0.0f, 50.0f)); mWalkList.AddLast(new Vector3(-100.0f, 0.0f, -200.0f)); mWalkList.AddLast(new Vector3(0.0f, 0.0f, 25.0f)); // Create knot objects so we can see movement ent = mSceneManager.CreateEntity("Knot1", "knot.mesh"); node = mSceneManager.GetRootSceneNode().CreateChildSceneNode("Knot1Node", new Vector3(0.0f, -10.0f, 25.0f)); node.AttachObject(ent); node.SetScale(0.1f, 0.1f, 0.1f); // ent = mSceneManager.CreateEntity("Knot2", "knot.mesh"); node = mSceneManager.GetRootSceneNode().CreateChildSceneNode("Knot2Node", new Vector3(550.0f, -10.0f, 50.0f)); node.AttachObject(ent); node.SetScale(0.1f, 0.1f, 0.1f); // ent = mSceneManager.CreateEntity("Knot3", "knot.mesh"); node = mSceneManager.GetRootSceneNode().CreateChildSceneNode("Knot3Node", new Vector3(-100.0f, -10.0f, -200.0f)); node.AttachObject(ent); node.SetScale(0.1f, 0.1f, 0.1f); // Set the camera to look at our handywork mCamera.SetPosition(90.0f, 280.0f, 535.0f); mCamera.Pitch(new Radian(new Degree(210.0f))); mCamera.Yaw(new Radian(new Degree(-15.0f))); mCamera.Roll(new Radian(new Degree(180.0f))); // Set idle animation mAnimationState = mEntity.GetAnimationState("Idle"); mAnimationState.SetLoop(true); mAnimationState.SetEnabled(true); } protected bool nextLocation() { if (mWalkList.Count == 0) return false; return true; } protected override bool FrameStarted(FrameEvent e) { if (mRenderWindow.Closed || mDone) return false; mDeltaTime = e.TimeSinceLastFrame; UpdateDebugOverlay(); if (!mWalking) //either we've not started walking or reached a way point { //check if there are places to go if (nextLocation()) { //Start the walk animation mAnimationState = mEntity.GetAnimationState("Walk"); mAnimationState.SetLoop(true); mAnimationState.SetEnabled(true); mWalking = true; //Update the destination using the walklist. LinkedListNode<Vector3> tmp; //temporary listNode mDestination = mWalkList.First.Value; //get the next destination. tmp = mWalkList.First; //save the node that held it mWalkList.RemoveFirst(); //remove that node from the front of the list mWalkList.AddLast(tmp); //add it to the back of the list. //update the direction and the distance mDirection = mDestination - mNode.GetPosition(); mDistance = mDirection.Normalize(); }//if(nextLocation()) else //nowhere to go. set the idle animation. (or Die) { mAnimationState = mEntity.GetAnimationState("Idle"); //mAnimationState = mEntity.GetAnimationState("Die"); //mAnimationState.SetLoop(false); } } else //we're in motion { //determine how far to move this frame float move = mWalkSpeed * mDeltaTime; mDistance -= move; if (mDistance <= 0.0f) { mNode.SetPosition(mDestination); mDirection = Vector3.Zero; //Check to see if we've arrived at a waypoint if (mDistance <= 0.0f) { //set our node to the destination we've just reached & reset direction to 0 mNode.SetPosition(mDestination); mDirection = Vector3.Zero; mWalking = false; }//if(mDistance <= 0.0f) } else { //movement code goes here mNode.Translate(mDirection * move); //Rotation code goes here Vector3 src = mNode.GetOrientation() * Vector3.UnitX; if ((1.0f + src.Dot(mDirection)) < 0.0001f) { mNode.Yaw(180.0f); } else { Quaternion quat = src.GetRotationTo(mDirection); mNode.Rotate(quat); } } } //Update the Animation State. mAnimationState.AddTime(mDeltaTime); return true; } [MTAThread] static void Main(string[] args) { using (MoveDemoApplication app = new MoveDemoApplication()) { app.Start(); } } } }
首先,注意红色代码部分,每个Entity对象都有一个GetAnimationState方法,用于取得其Animation State,robot.skeleton有Walk和Idle两种属性,设置loop true和enabled true,调用AddTime方法以设置动画速度。AddTime方法必须在FrameStarted或者FrameEnded中被调用,以使其在render时被刷新。
需要注意的是,骨骼动画是已经设置好的,代码只能让其按照脚本动作。
蓝色代码部分是设置位置和转向的。
这样,我们的robot就可以走动了。但是,今天,我试图使用ninja.mesh来做骨骼动画,却发现VS崩溃,无法调试,看代码,断点……整整一上午都没有找到问题所在,直到自己很巧合的在Windows下运行给出了错误提示:其实每个.skeleton文件中,定义的Animation State不一定一样,ninja.skeleton中就没有Idle这种状态,get当然会出错。
找到问题所在就容易解决了,两种方法:1.try catch 2.更换模型。