开发者

Can't get model bones to animate independently in XNA

I am trying to programmatically animate my character model in XNA. I started by looking at the code example here: http://create.msdn.com/en-US/education/catalog/sample/skinned_model By editing the code in this example I was able to get the character to move around as I liked. Then I tried to make a separate program with just the essential code to do this. (I borrowed the "dude" model from the example).

Here is my code:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace WindowsGame1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDevice device;
    GraphicsDeviceManager graphics;
    Model myModel;
    float aspectRatio;

    public Matrix[] boneTransforms;
    public Matrix[] originalBoneTransforms;
    Matrix[] worldTransforms;

    float pos = 0;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {
        device = graphics.GraphicsDevice;
        myModel = Content.Load<Model>("dude");

        worldTransforms = new Matrix[myModel.Bones.Count];
        boneTransforms = new Matrix[myModel.Bones.Count];
        originalBoneTransforms = new Matrix[myModel.Bones.Count];
        myModel.CopyAbsoluteBone开发者_如何学运维TransformsTo(boneTransforms);
        myModel.CopyAbsoluteBoneTransformsTo(originalBoneTransforms);


        aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
    }

    protected override void Update(GameTime gameTime)
    {
        UpdateBoneTransforms();
        UpdateWorldTransforms();

        base.Update(gameTime);
    }

    public void UpdateBoneTransforms()
    {
        pos += .1f;
        int boneId = 32; //Right Arm
        boneTransforms[boneId] = Matrix.CreateTranslation(new Vector3(0, pos, 0)) * originalBoneTransforms[boneId];
    }

    public void UpdateWorldTransforms()
    {
        // Root bone.
        worldTransforms[0] = boneTransforms[0];

        // Child bones.
        for (int bone = 1; bone < worldTransforms.Length; bone++)
        {
            int parentBone = myModel.Bones[bone].Parent.Index;

            worldTransforms[bone] = boneTransforms[bone] *
                                         worldTransforms[parentBone];
        }
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        Matrix view = Matrix.CreateLookAt(new Vector3(0, 150, 125),
                    Vector3.Zero, Vector3.Up);
        Matrix projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f), aspectRatio,
                    1.0f, 10000.0f);

        foreach (ModelMesh mesh in myModel.Meshes)
        {
            foreach (BasicEffect meshEffect in mesh.Effects)
            {
                meshEffect.EnableDefaultLighting();
                meshEffect.World = worldTransforms[mesh.ParentBone.Index];
                meshEffect.View = view;
                meshEffect.Projection = projection;

                meshEffect.SpecularColor = new Vector3(0.25f);
                meshEffect.SpecularPower = 16;
            }
            mesh.Draw();
        }

        base.Draw(gameTime);
    }
}
}

I can't figure out why this is not working. If I set boneId (in UpdateBoneTransforms) to 0, the whole model moves around as expected, but if I change boneId to anything else, he just stands still in the original position. I would have expected a single joint to move even if I did not update the children, but I can't even get that to happen. Am I forgetting something important?


Your code seems right but I bet you're not loading the model through the SkinnedModelProcessor. If you're not, your model is being drawn with a BasicEffect shader which not supports the skinning information hold on your model.

So:

1) Verify that dude.fbx uses SkinnedModelProcessor as content processor. For this you will have to include a reference to the SkinnedModelPipeline on your content project. Using this processor will make your model to use the right shader (SkinnedModel.fx).

2) You will have to use an AnimationPlayer to get the model pose (instead of using CopyAbsoluteBoneTransformsTo). Don't Update() the AnimationPlayer if you don't need animation.

3) To the resulting pose (a Matrix[]) do whatever transform you want.

4) Configure the SkinnedModelEffect with the pose (bones) and view and projection matrices:

effect.Parameters["Bones"].SetValue(bones);
effect.Parameters["View"].SetValue(view);
effect.Parameters["Projection"].SetValue(projection);

5) Draw.

All this stuff is in the Skinned Model sample code and you need it to use the skinning data.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜