#region Using Statements using System; using System.Threading; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using XSIXNARuntime; #endregion namespace SOFTIMAGE_XNAViewer { public class ModelAsset { public Model CrosswalkModel; public int AnimationIndex = 0; public int OldAnimationIndex = 0; public List Animations; public String FilePath; // 追加 public Matrix[] BoneTransforms; public float Blend = 1.0f; public TimeSpan CurrentTime; public bool Loop = true; public ModelAsset(String AssetPath, ContentManager content) { LoadContent(AssetPath, content); FilePath = AssetPath; } public void LoadContent(String AssetPath, ContentManager content) { CrosswalkModel = content.Load(AssetPath); Animations = new List(); // post process animation XSIAnimationData l_Animations = CrosswalkModel.Tag as XSIAnimationData; if (l_Animations != null) { foreach (KeyValuePair AnimationClip in l_Animations.RuntimeAnimationContentDictionary) { AnimationClip.Value.BindModelBones(CrosswalkModel); Animations.Add(AnimationClip.Value); } l_Animations.ResolveBones(CrosswalkModel); // 追加 // ボーンのトランスフォームを配列にコピーする BoneTransforms = new Matrix[CrosswalkModel.Bones.Count]; CrosswalkModel.CopyBoneTransformsTo(BoneTransforms); } } } /// /// This is the main type for your game /// public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; ContentManager content; private float FieldOfView; private Vector3 Position; private Vector3 Interest; private bool PlaybackStatus = true; private XSISASContainer SASData = new XSISASContainer(); private List Models; private ModelAsset LightsAndCam; private int CurrentModel = 0; private SpriteFont Font; private SpriteBatch FontWriter; private float AspectRatio; private int TotalElapsedFrames = 0; private int PlaybackSpeedDivider = 1; // 追加 private KeyboardState keyboardState; private KeyboardState lastKeyboardState; private int modelCounter = 1; public Game1() { graphics = new GraphicsDeviceManager(this); graphics.PreferMultiSampling = false; graphics.PreferredBackBufferWidth = 800; graphics.PreferredBackBufferHeight =600; // for NTSC, use a 4:3 ratio // graphics.PreferredBackBufferWidth = 720; // graphics.PreferredBackBufferHeight = 480; content = new ContentManager(Services); } /// /// 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. /// protected override void Initialize() { // TODO: Add your initialization logic here Position.X = 0.0f; Position.Y = 2.0f; Position.Z = 20.0f; Interest.X = 0.0f; Interest.Y = 0.0f; Interest.Z = 0.0f; FieldOfView = 45.0f; AspectRatio = 16.0f / 9.0f; // (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height; // AspectRatio = (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height; base.Initialize(); } /// /// Load your graphics content. If loadAllContent is true, you should /// load content from both ResourceManagementMode pools. Otherwise, just /// load ResourceManagementMode.Manual content. /// /// Which type of content to load. protected override void LoadContent() { // initialize lights by default XSISASPointLight light1 = new XSISASPointLight(); XSISASPointLight light2 = new XSISASPointLight(); XSISASPointLight light3 = new XSISASPointLight(); light1.Color = new Vector4(0.7f, 0.7f, 0.7f, 1.0f); light2.Color = new Vector4(0.7f, 0.7f, 0.7f, 1.0f); light3.Color = new Vector4(0.7f, 0.7f, 0.7f, 1.0f); light1.Position = new Vector4(100.0f, 100.0f, 100.0f, 1.0f); light2.Position = new Vector4(-100.0f, 100.0f, 100.0f, 1.0f); light3.Position = new Vector4(0.0f, 0.0f, -100.0f, 1.0f); light1.Range = 10000.0f; light2.Range = 10000.0f; light3.Range = 10000.0f; SASData.PointLights.Add(light1); SASData.PointLights.Add(light2); SASData.PointLights.Add(light3); Font = content.Load("Content/DefaultFont"); FontWriter = new SpriteBatch(graphics.GraphicsDevice); Models = new List(); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); Models.Add(new ModelAsset("Content/Models/Captain_ModTool", content)); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); Models.Add(new ModelAsset("Content/Models/Captain_ModTool", content)); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); Models.Add(new ModelAsset("Content/Models/Captain_ModTool", content)); Models.Add(new ModelAsset("Content/Models/Robot_Articulated", content)); LightsAndCam = new ModelAsset("Content/Models/scene_data", content); Matrix[] LightsAndCamTransforms = new Matrix[LightsAndCam.CrosswalkModel.Bones.Count]; LightsAndCam.CrosswalkModel.CopyAbsoluteBoneTransformsTo(LightsAndCamTransforms); Matrix CameraPosition = LightsAndCamTransforms[LightsAndCam.CrosswalkModel.Bones["Camera"].Index]; Matrix CameraInterest = LightsAndCamTransforms[LightsAndCam.CrosswalkModel.Bones["Camera_Interest"].Index]; // Set the initial camera position Position = CameraPosition.Translation; Interest = CameraInterest.Translation; // TODO: Load any ResourceManagementMode.Automatic content // TODO: Load any ResourceManagementMode.Manual content } /// /// Unload your graphics content. If unloadAllContent is true, you should /// unload content from both ResourceManagementMode pools. Otherwise, just /// unload ResourceManagementMode.Manual content. Manual content will get /// Disposed by the GraphicsDevice during a Reset. /// /// Which type of content to unload. protected override void UnloadContent() { content.Unload(); } private void UpdateGamePad() { GamePadState state = GamePad.GetState(PlayerIndex.One); if ((state.Buttons.Back == ButtonState.Pressed) && (state.Buttons.Start == ButtonState.Pressed)) Exit(); // 追加 lastKeyboardState = keyboardState; keyboardState = Keyboard.GetState(); // 追加 // if (state.DPad.Left == ButtonState.Pressed) if ((state.DPad.Left == ButtonState.Pressed) || (lastKeyboardState.IsKeyDown(Keys.Left) != true && keyboardState.IsKeyDown(Keys.Left) == true)) { if (Models[CurrentModel].Animations.Count > 0) { Models[CurrentModel].AnimationIndex--; if (Models[CurrentModel].AnimationIndex < 0) Models[CurrentModel].AnimationIndex = Models[CurrentModel].Animations.Count - 1; System.Threading.Thread.Sleep(200); // 追加 // Blend = 0.0f; Models[CurrentModel].Blend = 0.0f; } } // 追加 // if (state.DPad.Right == ButtonState.Pressed) if ((state.DPad.Right == ButtonState.Pressed) || (lastKeyboardState.IsKeyDown(Keys.Right) != true && keyboardState.IsKeyDown(Keys.Right) == true)) { if (Models[CurrentModel].Animations.Count > 0) { Models[CurrentModel].AnimationIndex++; if (Models[CurrentModel].AnimationIndex >= Models[CurrentModel].Animations.Count) Models[CurrentModel].AnimationIndex = 0; System.Threading.Thread.Sleep(200); // 追加 // Blend = 0.0f; Models[CurrentModel].Blend = 0.0f; } } // 追加 // if (state.DPad.Up == ButtonState.Pressed) if ((state.DPad.Up == ButtonState.Pressed) || (lastKeyboardState.IsKeyDown(Keys.Up) != true && keyboardState.IsKeyDown(Keys.Up) == true)) { CurrentModel = CurrentModel + 1; if (CurrentModel >= Models.Count) CurrentModel = 0; System.Threading.Thread.Sleep(200); } // 追加 // if (state.DPad.Down == ButtonState.Pressed) if ((state.DPad.Down == ButtonState.Pressed) || (lastKeyboardState.IsKeyDown(Keys.Down) != true && keyboardState.IsKeyDown(Keys.Down) == true)) { CurrentModel = CurrentModel - 1; if (CurrentModel < 0) CurrentModel = Models.Count - 1; System.Threading.Thread.Sleep(200); } // 追加 if (lastKeyboardState.IsKeyDown(Keys.I) != true && keyboardState.IsKeyDown(Keys.I) == true) { // モデルの追加 modelCounter++; if (modelCounter > Models.Count) modelCounter = Models.Count; } // 追加 if (lastKeyboardState.IsKeyDown(Keys.P) != true && keyboardState.IsKeyDown(Keys.P) == true) { // カレントモデルのモーションのタイミングを初期化する Models[CurrentModel].CurrentTime = TimeSpan.Parse("00:00:00"); } // 追加 if (lastKeyboardState.IsKeyDown(Keys.L) != true && keyboardState.IsKeyDown(Keys.L) == true) { // 全モデルのモーションのタイミングを初期化する for (int i = 0; i < modelCounter; i++) Models[i].CurrentTime = TimeSpan.Parse("00:00:00"); } } /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input and playing audio. /// /// Provides a snapshot of timing values. protected override void Update(GameTime gameTime) { TimeSpan ElapsedTime = TimeSpan.FromTicks(gameTime.ElapsedGameTime.Ticks / PlaybackSpeedDivider); // TODO: Add your update logic here UpdateGamePad(); // 追加 for (int i = 0; i < modelCounter; i++) { if ((Models[i].Animations != null) && (Models[i].Animations.Count > 0)) { // 追加 // 復元 Models[i].CrosswalkModel.CopyBoneTransformsFrom(Models[i].BoneTransforms); Models[i].Animations[Models[i].AnimationIndex].CurrentTime = Models[i].CurrentTime; if (PlaybackStatus) { if (Models[i].Animations.Count > 0) { if (Models[i].Blend < 1.0f) { Models[i].Animations[Models[i].OldAnimationIndex].PlayBack(TimeSpan.Parse("0"), 1.0f); Models[i].Blend += 0.1f; if (Models[i].Blend > 1.0f) Models[i].Blend = 1.0f; } else { Models[i].OldAnimationIndex = Models[i].AnimationIndex; } Models[i].Animations[Models[i].AnimationIndex].PlayBack(ElapsedTime, Models[i].Blend); } } else { Models[i].Animations[Models[i].AnimationIndex].PlayBack(TimeSpan.Parse("00:00:00"), 1.0f); } // 追加 // 退避 Models[i].CrosswalkModel.CopyBoneTransformsTo(Models[i].BoneTransforms); Models[i].CurrentTime = Models[i].Animations[Models[i].AnimationIndex].CurrentTime; } } Matrix[] LightsAndCamTransforms = new Matrix[LightsAndCam.CrosswalkModel.Bones.Count]; LightsAndCam.CrosswalkModel.CopyAbsoluteBoneTransformsTo(LightsAndCamTransforms); base.Update(gameTime); } // 追加 // private void DrawModel(Model m) private void DrawModel(Model m, Matrix world, Matrix[] BoneTransforms) { // post process animation XSIAnimationData l_Animations = m.Tag as XSIAnimationData; Matrix[] transforms = new Matrix[m.Bones.Count]; // 追加 // 復元 m.CopyBoneTransformsFrom(BoneTransforms); // ワールド座標セット m.Root.Transform = world; m.CopyAbsoluteBoneTransformsTo(transforms); bool isSkinned = false; Matrix[] bones = null; if (l_Animations != null) { l_Animations.ComputeBoneTransforms(transforms); bones = l_Animations.BoneTransforms; if (bones.Length > 0) isSkinned = true; } foreach (ModelMesh mesh in m.Meshes) { SASData.Model = transforms[mesh.ParentBone.Index]; // 追加 // ワールド座標セット // SASData.Model = world; SASData.ComputeModel(); foreach (Effect effect in mesh.Effects) { if (effect.GetType() == typeof(BasicEffect)) { BasicEffect basiceffect = (BasicEffect)effect; basiceffect.EnableDefaultLighting(); basiceffect.PreferPerPixelLighting = true; basiceffect.Alpha = 0.5f; basiceffect.View = SASData.View; basiceffect.Projection = SASData.Projection; basiceffect.World = SASData.Model; } else { // set the technique if (isSkinned && (effect.Techniques["Skinned"] != null)) { effect.CurrentTechnique = effect.Techniques["Skinned"]; } else { if (effect.Techniques["Static"] != null) { effect.CurrentTechnique = effect.Techniques["Static"]; } else { effect.CurrentTechnique = effect.Techniques[0]; } } if (isSkinned) { if ((effect.Parameters["Bones"] != null) && isSkinned) { effect.Parameters["Bones"].SetValue(bones); } } // bind all other parameters foreach (EffectParameter Parameter in effect.Parameters) { SASData.SetEffectParameterValue(Parameter); } } } mesh.Draw(); } } /// /// This is called when the game should draw itself. /// /// Provides a snapshot of timing values. protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.Gray); graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false; graphics.GraphicsDevice.RenderState.DepthBufferEnable = true; graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true; graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace; TotalElapsedFrames++; // TODO: Add your drawing code here SASData.Camera.NearFarClipping.X = 1.0f; SASData.Camera.NearFarClipping.Y = 10000.0f; SASData.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(FieldOfView), AspectRatio, SASData.Camera.NearFarClipping.X, SASData.Camera.NearFarClipping.Y); SASData.View = Matrix.CreateLookAt(Position, Interest, Vector3.Up); SASData.ComputeViewAndProjection(); // 追加 for (int i = 0; i < modelCounter; i++) { // ワールド座標変換行列 float testScale = 0.1f; float testRot = 0f; Vector3 testPos = new Vector3(i * 4 - 4, 0, 0); if (i > 4) testPos = new Vector3((i - 5) * 4 - 4, -8, 0); Matrix world1 = Matrix.CreateScale(testScale) // 拡大・縮小 * Matrix.CreateRotationY(MathHelper.ToRadians(testRot)) // 回転 * Matrix.CreateTranslation(testPos); // 移動 DrawModel(Models[i].CrosswalkModel, world1, Models[i].BoneTransforms); } // Status FontWriter.Begin(); String Message; #if XBOX int safezone = 30; #else int safezone = 0; #endif // 追加 Message = "CurrentModel No : " + CurrentModel.ToString(); FontWriter.DrawString(Font, Message, new Vector2(safezone + 10, safezone + 200), new Color(255, 255, 0)); Message = "Push I Key : Add Model"; FontWriter.DrawString(Font, Message, new Vector2(safezone + 10, safezone + 250), new Color(255, 255, 0)); Message = "Push P Key : Initialized CurrentTime (Current Model)"; FontWriter.DrawString(Font, Message, new Vector2(safezone + 10, safezone + 270), new Color(255, 255, 0)); Message = "Push L Key : Initialized CurrentTime (All Model)"; FontWriter.DrawString(Font, Message, new Vector2(safezone + 10, safezone + 290), new Color(255, 255, 0)); FontWriter.End(); base.Draw(gameTime); } } }