К основному контенту

3D Animation: XNAnimation

Три дня бился об стол, но разобрался. Все-таки для моего уровня пока не разобраться с трехмерной анимации без сторонних библиотек, разбираем XNAnimatinon.

Результат

Нам понадобиться

  • Библиотека XNAnimatinon http://xnanimation.codeplex.com/,
  • Microsoft Visual C# 2008 Express Edition,
  • XNA 3.1
  • моделька с анимацией и текстурами формата fbx (я взял с примеров XNAnimation).

Что делаем?
Создаем программку, которая будет отображать трехмерную анимацию персонажа. Модель имеет несколько анимаций, - по нажатию на пробел воспроизводиться следующая анимация персонажа и так по кругу.

Как это реализовать?
К сожалению, стандартными методами данную задачу не реализовать, в XNA отсутствует свой обработчик анимации, базовый пример как это реализовать находиться по адресу http://creators.xna.com/en-US/sample/skinnedmodel. В XNA есть реализация чтения модели из fbx файла, но не более, исключение составляет ситуация, если вы будете управлять анимацией посредством костей в модельке - что приемлемо для не сложных анимаций (пример http://creators.xna.com/sample/simpleanimation). Чтобы прочитать анимацию из fbx нужно подставить вместо стандартного загрузчика модельки свой.

Подготавливаем надстройки.
Из XNAnimatinon, вытягиваем две библиотеки: XNAnimation.dll, XNAnimationPipeline.dll

На XNAnimation ссылаемся в общем проекте, а на XNAnimationPipeline ссылаемся в загрузчике (Content).

Так же в Content создаем 2-е папки Models и Textures, куда указываем модельку fbx и текстуры, соответственно.

Теперь нужно указать явно - через что загружать модельку. Указываем в свойствах модельки загрузчик

Content Processor = Model XNAnimation, Generate TangentFrame = true, путь к текстурам Texture Path = ..\Textures\

Теперь мы готовы к коду, привожу с комментариями.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
//Подключаем области из библиотеки анимации
using XNAnimation;
using XNAnimation.Controllers;
using XNAnimation.Effects;

namespace _3dAnimationTest
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        /// 
        /// Модель
        /// 
        SkinnedModel skinnedModel;
        /// 
        /// Контроллер анимации
        /// 
        AnimationController animationController;
        /// 
        /// Матрица вида
        /// 
        Matrix cameraView;
        /// 
        /// Матрица проекции
        /// 
        Matrix cameraProjection;
        /// 
        /// Индекс анимации
        /// 
        int animationIndex = 0;
        /// 
        /// Состояние нажатых клавиш
        /// 
        KeyboardState kb;
        /// 
        /// Старое состояние нажатых клавищ
        /// 
        KeyboardState Oldkb;
        /// 
        /// Конструктор
        /// 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            //Антиальясинг включить
            graphics.PreferMultiSampling = true;
        }
        /// 
        /// Инициализация
        /// 
        protected override void Initialize()
        {
            base.Initialize();
        }
        /// 
        /// Загрузка данных
        /// 
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            //Загрузка модели
            skinnedModel = Content.Load("Models\\PlayerMarine");
            //Присвоение контроллера анимации
            animationController = new AnimationController(skinnedModel.SkeletonBones);
            //Воспроизводить анимацию по индексу
            animationController.StartClip(skinnedModel.AnimationClips.Values[animationIndex]);
            //Матрицы вида и проекции встраиваються
            cameraView = Matrix.CreateLookAt(new Vector3(10, 15, 30), new Vector3(0, 14, 0), Vector3.Up);
            cameraProjection = Matrix.CreatePerspectiveFieldOfView(1, 1, 1, 1000);
        }
        /// 
        /// Выгрузка данных
        /// 

        protected override void UnloadContent()
        {
        }
        /// 
        /// Обновление данных
        /// 
        /// Игровое время
        protected override void Update(GameTime gameTime)
        {
            //Вычисляем нажатые клавиши, по нажатию пробел - анимация меняеться на следующую (всего 3 анимации)
            //Опознаем нажатые клавиши
            kb = Keyboard.GetState();
            //Если нажат пробел и он был отпущен ранее
            if (kb.IsKeyDown(Keys.Space) && kb!=Oldkb)
            {
                //Анимационный индекс = следующему из трех
                animationIndex = ++animationIndex % 3;
                //Крутим анимацию уже следующего индекса
                animationController.StartClip(skinnedModel.AnimationClips.Values[animationIndex]);
            }
            //Запоминаем нажатые клавиши
            Oldkb = kb;
            //Обновляем анимацию
            animationController.Update(gameTime.ElapsedGameTime, Matrix.Identity);
            base.Update(gameTime);
        }
        /// 
        /// Отображаем данные
        /// 
        /// Игровое время
        protected override void Draw(GameTime gameTime)
        {
            //Очищаем
            GraphicsDevice.Clear(Color.CornflowerBlue);
            //Каждый меш модели
            foreach (ModelMesh modelMesh in skinnedModel.Model.Meshes)
            {
                //Каждый элемент меша
                foreach (SkinnedModelBasicEffect effect in modelMesh.Effects)
                {
                    // Устанавливаем камеру
                    effect.View = cameraView;
                    effect.Projection = cameraProjection;
                    // Устанавливаем анимацию (транфрмацию) костей к модели
                    effect.Bones = animationController.SkinnedBoneTransforms;
                    // Настраиваем материал (если надо)
                    effect.Material.DiffuseColor = new Vector3(0.8f);
                    effect.Material.SpecularColor = new Vector3(0.3f);
                    effect.Material.SpecularPower = 8;
                    // Настраиваем свет (если надо)
                    effect.AmbientLightColor = new Vector3(0.1f);
                    effect.LightEnabled = true;
                    effect.EnabledLights = EnabledLights.One;
                    effect.PointLights[0].Color = Vector3.One;
                    effect.PointLights[0].Position = new Vector3(100);
                }
                // Рисуем меш
                modelMesh.Draw();
            }
            base.Draw(gameTime);
        }
    }
}
Архив файла проекта (перед компиляцией переподключите билиотеки из корня).

Комментарии

Отправить комментарий