ビルボードのビルさん再び

■「ビルボードのビルさん」では、カメラが回転している場合のビルボードでしたが、
ゲームでは、カメラよりモデルが回転している場合が多いのです。

namespace WindowsGame2_08
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        private float dAng1 = 0;
        private float dAng2 = 0;
        private Model model;
        private Matrix mainView;
        private Matrix viewInvert;
        private Matrix mainWorld;
        private Matrix mainProjection;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        protected override void Initialize()
        {
            model = Content.Load<Model>("Box");
            mainProjection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f),
                    (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height,
                    1.0f,
                    100.0f
                );
            mainWorld = Matrix.CreateTranslation(0, 0, 0);
            // ビューマトリックス
            mainView = Matrix.CreateLookAt(
                    new Vector3(10.0f, 5.0f, 0.0f),
                    new Vector3(0, 0, 0),
                    Vector3.Up
                );
            viewInvert = Matrix.Invert(mainView);
            viewInvert.M14 = 0.0f;
            viewInvert.M24 = 0.0f;
            viewInvert.M34 = 0.0f;
            viewInvert.M41 = 0.0f;
            viewInvert.M42 = 0.0f;
            viewInvert.M43 = 0.0f;
            viewInvert.M44 = 1.0f;
            base.Initialize();
        }

        protected override void Update(GameTime gameTime)
        {
            dAng1 += 0.01f;
            if (dAng1 > 3.141592f * 2)
                dAng1 -= 3.141592f * 2;
            dAng2 += 0.03f;
            if (dAng2 > 3.141592f * 2)
                dAng2 -= 3.141592f * 2;
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            Matrix mWang;
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            for (int j = -4; j < 5; j++)
            {
                for (int i = -4; i < 5; i++)
                {
                    mWang = Matrix.CreateTranslation(i * 3.0f, 0.0f, j * 3.0f) * Matrix.CreateRotationX(dAng1) * Matrix.CreateRotationY(dAng2);
                    mainWorld = viewInvert * mWang;
                    foreach (ModelMesh mesh in model.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.View = mainView;
                            effect.World = mainWorld;
                            effect.Projection = mainProjection;
                        }
                        mesh.Draw();
                    }
                }
            }
            base.Draw(gameTime);
        }
    }
}

にすると、またビルさんにそっぽを向かれます。

■ですので、また逆ベクトルをかけてやる必要がでてきます。

protected override void Draw(GameTime gameTime)
{
    Matrix mWang;
    Matrix mWinvert;
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    for (int j = -4; j < 5; j++)
    {
        for (int i = -4; i < 5; i++)
        {
            mWang = Matrix.CreateTranslation(i * 3.0f, 0.0f, j * 3.0f) * Matrix.CreateRotationX(dAng1) * Matrix.CreateRotationY(dAng2);
            mWinvert = Matrix.Invert(mWang);
            mWinvert.M14 = 0.0f;
            mWinvert.M24 = 0.0f;
            mWinvert.M34 = 0.0f;
            mWinvert.M41 = 0.0f;
            mWinvert.M42 = 0.0f;
            mWinvert.M43 = 0.0f;
            mWinvert.M44 = 1.0f;
            mainWorld = viewInvert * mWinvert * mWang;
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.View = mainView;
                    effect.World = mainWorld;
                    effect.Projection = mainProjection;
                }
                mesh.Draw();
            }
        }
    }
    base.Draw(gameTime);
}

ビルさんが、また、こっちを向いてくれました。

■実際は、下の部分でトランスレートとスケールの部分を殺す役割をしているので

mWinvert.M14 = 0.0f;
mWinvert.M24 = 0.0f;
mWinvert.M34 = 0.0f;
mWinvert.M41 = 0.0f;
mWinvert.M42 = 0.0f;
mWinvert.M43 = 0.0f;
mWinvert.M44 = 1.0f;

このように書いても同じ意味になります。

mWang = Matrix.CreateRotationX(dAng1) * Matrix.CreateRotationY(dAng2);
mWinvert = Matrix.Invert(mWang);
mainWorld = viewInvert * mWinvert * Matrix.CreateTranslation(i * 3.0f, 0.0f, j * 3.0f) * mWang;
foreach (ModelMesh mesh in model.Meshes)
{
    foreach (BasicEffect effect in mesh.Effects)
    {
        effect.View = mainView;
        effect.World = mainWorld;
        effect.Projection = mainProjection;
    }
    mesh.Draw();
}

■逆ベクトル?

mWang = Matrix.CreateRotationX(dAng1) * Matrix.CreateRotationY(dAng2);
mWinvert = Matrix.Invert(mWang);

回転が逆という事であれば

mWang = Matrix.CreateRotationX(dAng1) * Matrix.CreateRotationY(dAng2);
mWinvert = Matrix.CreateRotationY(-dAng2) * Matrix.CreateRotationX(-dAng1);

と同じ事になります。(多分、Invertで逆ベクトルを求めるよりは軽いかな?)
最終的に整理すると、こんなソースになります。

protected override void Draw(GameTime gameTime)
{
    Matrix mWang    = Matrix.CreateRotationX(dAng1) * Matrix.CreateRotationY(dAng2);
    Matrix mWinvert = viewInvert * Matrix.CreateRotationY(-dAng2) * Matrix.CreateRotationX(-dAng1);
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    for (int j = -4; j < 5; j++)
    {
        for (int i = -4; i < 5; i++)
        {
            mainWorld = mWinvert * Matrix.CreateTranslation(i * 3.0f, 0.0f, j * 3.0f) * mWang;
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.View = mainView;
                    effect.World = mainWorld;
                    effect.Projection = mainProjection;
                }
                mesh.Draw();
            }
        }
    }
    base.Draw(gameTime);
}