无法在XNA中使模型骨骼独立动画

时间:2011-07-26 05:17:25

标签: c# animation xna

我正在尝试以编程方式在XNA中为我的角色模型制作动画。我从这里查看代码示例开始: http://create.msdn.com/en-US/education/catalog/sample/skinned_model 通过编辑此示例中的代码,我能够让角色按照我喜欢的方式移动。然后我尝试使用基本代码创建一个单独的程序来执行此操作。 (我从例子中借用了“dude”模型)。

这是我的代码:

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.CopyAbsoluteBoneTransformsTo(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);
    }
}
}

我无法弄清楚为什么这不起作用。如果我将boneId(在UpdateBoneTransforms中)设置为0,整个模型会按预期移动,但如果我将boneId更改为其他任何东西,他只会站在原始位置。即使我没有更新孩子,我也会期待一个关节可以移动,但我甚至无法实现这一点。我忘记了重要的事情吗?

1 个答案:

答案 0 :(得分:1)

您的代码似乎正确,但我敢打赌您没有通过SkinnedModelProcessor加载模型。如果不是,则使用BasicEffect着色器绘制模型,该着色器不支持模型上的蒙皮信息。

所以:

1)验证dude.fbx使用SkinnedModelProcessor作为内容处理器。为此,您必须在内容项目中包含对SkinnedModelPipeline的引用。使用此处理器将使您的模型使用正确的着色器(SkinnedModel.fx)。

2)您必须使用AnimationPlayer来获取模型姿势(而不是使用CopyAbsoluteBoneTransformsTo)。如果您不需要动画,请不要更新()动画播放器。

3)对结果姿势(矩阵[])做任何你想要的变换。

4)使用pose(骨骼)和视图和投影矩阵配置SkinnedModelEffect:

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

5)画画。

所有这些东西都在皮肤模型示例代码中,您需要它来使用皮肤数据。