Не удается заставить моделируемые кости анимироваться независимо в XNA - PullRequest
2 голосов
/ 26 июля 2011

Я пытаюсь программно анимировать свою модель персонажа в XNA. Я начал с просмотра примера кода здесь: http://create.msdn.com/en-US/education/catalog/sample/skinned_model Отредактировав код в этом примере, я смог заставить персонажа двигаться так, как мне нравится. Затем я попытался создать отдельную программу, содержащую только необходимый код для этого. (Я позаимствовал модель "чувак" из примера).

Вот мой код:

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 Ответ

1 голос
/ 27 июля 2011

Ваш код кажется правильным, но я уверен, что вы не загружаете модель через SkinnedModelProcessor. Если это не так, ваша модель рисуется с помощью шейдера BasicEffect, который не поддерживает информацию о скинах, хранящуюся в вашей модели.

Итак:

1) Убедитесь, что dude.fbx использует SkinnedModelProcessor в качестве процессора содержимого. Для этого вам нужно будет включить ссылку на SkinnedModelPipeline в ваш контент-проект. Использование этого процессора заставит вашу модель использовать правильный шейдер (SkinnedModel.fx).

2) Вам придется использовать AnimationPlayer для получения позы модели (вместо использования CopyAbsoluteBoneTransformsTo). Не обновляйте () AnimationPlayer, если вам не нужна анимация.

3) Для получающейся позы (Матрицы []) сделайте любое преобразование, которое вы хотите.

4) Настройте SkinnedModelEffect с помощью матриц позы (кости) и вида и проекции:

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

5) Ничья.

Все это есть в примере кода Skinned Model, и вам нужно использовать данные скинов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...