ビルボードのビルさん再び
■「ビルボードのビルさん」では、カメラが回転している場合のビルボードでしたが、
ゲームでは、カメラよりモデルが回転している場合が多いのです。
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); }