XNA: Rotating Bones

Posted by MLM on Game Development See other posts from Game Development or by MLM
Published on 2012-05-26T23:50:26Z Indexed on 2012/09/12 15:52 UTC
Read the original article Hit count: 416

Filed under:
|
|
|
|

XNA 4.0

I am trying to learn how to rotate bones on a very simple tank model I made in Cinema 4D.

It is rigged by 3 bones, Root -> Main -> Turret -> Barrel

I have binded all of the objects to the bones so that all translations/rotations work as planned in C4D. I exported it as .fbx

I based my test project after: http://create.msdn.com/en-US/education/catalog/sample/simple_animation

I can build successfully with no errors but all the rotations I try to do to my bones have no effect. I can transform my Root successfully using below but the bone transforms have no effect:

myModel.Root.Transform = world;

Matrix turretRotation = Matrix.CreateRotationY(MathHelper.ToRadians(37));
Matrix barrelRotation = Matrix.CreateRotationX(barrelRotationValue);

MainBone.Transform = MainTransform;
TurretBone.Transform = turretRotation * TurretTransform;
BarrelBone.Transform = barrelRotation * BarrelTransform;

I am wondering if my model is just not right or something important I am missing in the code.

Here is my Game1.cs

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 ModelTesting
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        float aspectRatio;

        Tank myModel;

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

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            myModel = new Tank();

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            myModel.Load(Content);
            aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            float time = (float)gameTime.TotalGameTime.TotalSeconds;

            // Move the pieces
            /*
            myModel.TurretRotation = (float)Math.Sin(time * 0.333f) * 1.25f;
            myModel.BarrelRotation = (float)Math.Sin(time * 0.25f) * 0.333f - 0.333f;
            */

            base.Update(gameTime);
        }



        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // Calculate the camera matrices.
            float time = (float)gameTime.TotalGameTime.TotalSeconds;

            Matrix rotation = Matrix.CreateRotationY(MathHelper.ToRadians(45));

            Matrix view = Matrix.CreateLookAt(new Vector3(2000, 500, 0),
                                              new Vector3(0, 150, 0),
                                              Vector3.Up);

            Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                                    graphics.GraphicsDevice.Viewport.AspectRatio,
                                                                    10,
                                                                    10000);

            // TODO: Add your drawing code here
            myModel.Draw(rotation, view, projection);

            base.Draw(gameTime);
        }




    }
}

And here is my tank class:

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 ModelTesting
{

    public class Tank
    {
        Model myModel;

        // Array holding all the bone transform matrices for the entire model.
        // We could just allocate this locally inside the Draw method, but it
        // is more efficient to reuse a single array, as this avoids creating
        // unnecessary garbage.
        public Matrix[] boneTransforms;

        // Shortcut references to the bones that we are going to animate.
        // We could just look these up inside the Draw method, but it is more
        // efficient to do the lookups while loading and cache the results.
        ModelBone MainBone;
        ModelBone TurretBone;
        ModelBone BarrelBone;

        // Store the original transform matrix for each animating bone.
        Matrix MainTransform;
        Matrix TurretTransform;
        Matrix BarrelTransform;

        // current animation positions
        float turretRotationValue;
        float barrelRotationValue;

        /// <summary>
        /// Gets or sets the turret rotation amount.
        /// </summary>
        public float TurretRotation
        {
            get { return turretRotationValue; }
            set { turretRotationValue = value; }
        }

        /// <summary>
        /// Gets or sets the barrel rotation amount.
        /// </summary>
        public float BarrelRotation
        {
            get { return barrelRotationValue; }
            set { barrelRotationValue = value; }
        }


        /// <summary>
        /// Load the model
        /// </summary>
        public void Load(ContentManager Content)
        {
            // TODO: use this.Content to load your game content here
            myModel = Content.Load<Model>("Models\\simple_tank02");

            MainBone = myModel.Bones["Main"];
            TurretBone = myModel.Bones["Turret"];
            BarrelBone = myModel.Bones["Barrel"];

            MainTransform = MainBone.Transform;
            TurretTransform = TurretBone.Transform;
            BarrelTransform = BarrelBone.Transform;

            // Allocate the transform matrix array.
            boneTransforms = new Matrix[myModel.Bones.Count];
        }


        public void Draw(Matrix world, Matrix view, Matrix projection)
        {
            myModel.Root.Transform = world;

            Matrix turretRotation = Matrix.CreateRotationY(MathHelper.ToRadians(37));
            Matrix barrelRotation = Matrix.CreateRotationX(barrelRotationValue);

            MainBone.Transform = MainTransform;
            TurretBone.Transform = turretRotation * TurretTransform;
            BarrelBone.Transform = barrelRotation * BarrelTransform;

            myModel.CopyAbsoluteBoneTransformsTo(boneTransforms);

            // Draw the model, a model can have multiple meshes, so loop
            foreach (ModelMesh mesh in myModel.Meshes)
            {
                // This is where the mesh orientation is set
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = boneTransforms[mesh.ParentBone.Index];
                    effect.View = view;
                    effect.Projection = projection;

                    effect.EnableDefaultLighting();
                }

                // Draw the mesh, will use the effects set above
                mesh.Draw();
            }
        }


    }
}

© Game Development or respective owner

Related posts about XNA

Related posts about 3d