• R/O
  • SSH
  • HTTPS

mmdx: Commit


Commit MetaInfo

Revision904 (tree)
Time2011-08-06 02:14:23
Authorwilfrem

Log Message

ゼロフレームモーション/表情なしモデル/ブレンディングのバグを修正。あと、ブレンディングのデモを追加

Change Summary

Incremental Difference

--- trunk/MikuMikuDanceXNADemo6/MikuMikuDanceXNADemo6/Program.cs (nonexistent)
+++ trunk/MikuMikuDanceXNADemo6/MikuMikuDanceXNADemo6/Program.cs (revision 904)
@@ -0,0 +1,21 @@
1+using System;
2+
3+namespace MikuMikuDanceXNADemo6
4+{
5+#if WINDOWS || XBOX
6+ static class Program
7+ {
8+ /// <summary>
9+ /// アプリケーションのメイン エントリー ポイントです。
10+ /// </summary>
11+ static void Main(string[] args)
12+ {
13+ using (Game1 game = new Game1())
14+ {
15+ game.Run();
16+ }
17+ }
18+ }
19+#endif
20+}
21+
--- trunk/MikuMikuDanceXNADemo6/MikuMikuDanceXNADemo6/Properties/AssemblyInfo.cs (nonexistent)
+++ trunk/MikuMikuDanceXNADemo6/MikuMikuDanceXNADemo6/Properties/AssemblyInfo.cs (revision 904)
@@ -0,0 +1,34 @@
1+using System.Reflection;
2+using System.Runtime.CompilerServices;
3+using System.Runtime.InteropServices;
4+
5+// アセンブリに関する全般的な情報は、以下の一連の属性によって管理されます。
6+// アセンブリに関連付けられている情報を変更するには、これらの属性値を変更します。
7+//
8+[assembly: AssemblyTitle("MikuMikuDanceXNADemo6")]
9+[assembly: AssemblyProduct("MikuMikuDanceXNADemo6")]
10+[assembly: AssemblyDescription("")]
11+[assembly: AssemblyCompany("Microsoft")]
12+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
13+[assembly: AssemblyTrademark("")]
14+[assembly: AssemblyCulture("")]
15+
16+// ComVisible 属性を False に設定すると、このアセンブリに含まれる型が
17+// COM コンポーネントに公開されません。COM からこのアセンブリの型にアクセスする必要がある場合は、
18+// その型の ComVisible 属性を True に設定してください。
19+// Windows アセンブリだけが COM に対応しています。
20+[assembly: ComVisible(false)]
21+
22+// Windows 上では、このプロジェクトが COM に公開されている場合、 次の GUID が typelib の ID として設定されます。
23+// Windows 以外のプラットフォームでは、このアセンブリをデバイスに展開するときに
24+// タイトル ストレージ コンテナーを一意に識別するために使用します。
25+[assembly: Guid("75e5b326-fe9e-48c4-8546-78521ddfb2f2")]
26+
27+// アセンブリのバージョン情報は、次の 4 つの値で構成されています。
28+//
29+// メジャー バージョン
30+// マイナー バージョン
31+// ビルド番号
32+// リビジョン番号
33+//
34+[assembly: AssemblyVersion("1.0.0.0")]
--- trunk/MikuMikuDanceXNADemo6/MikuMikuDanceXNADemo6/Game1.cs (nonexistent)
+++ trunk/MikuMikuDanceXNADemo6/MikuMikuDanceXNADemo6/Game1.cs (revision 904)
@@ -0,0 +1,151 @@
1+using System;
2+using System.Collections.Generic;
3+using System.Linq;
4+using Microsoft.Xna.Framework;
5+using Microsoft.Xna.Framework.Audio;
6+using Microsoft.Xna.Framework.Content;
7+using Microsoft.Xna.Framework.GamerServices;
8+using Microsoft.Xna.Framework.Graphics;
9+using Microsoft.Xna.Framework.Input;
10+using Microsoft.Xna.Framework.Media;
11+using MikuMikuDance.Core.Model;
12+using MikuMikuDance.Core.Motion;
13+using MikuMikuDance.XNA;
14+
15+namespace MikuMikuDanceXNADemo6
16+{
17+ /// <summary>
18+ /// モーションブレンディングのデモ
19+ /// モーションブレンディングを行うことで2つのモーションをスムースにつなげることができます。
20+ /// </summary>
21+ public class Game1 : Microsoft.Xna.Framework.Game
22+ {
23+ GraphicsDeviceManager graphics;
24+
25+ MMDModel model;
26+ MMDMotion motion1, motion2;
27+
28+ decimal FactorPosition = 0m;
29+ decimal FactorVelocity = 0m;
30+
31+ public Game1()
32+ {
33+ graphics = new GraphicsDeviceManager(this);
34+ Content.RootDirectory = "Content";
35+ }
36+
37+ /// <summary>
38+ /// ゲームが実行を開始する前に必要な初期化を行います。
39+ /// ここで、必要なサービスを照会して、関連するグラフィック以外のコンテンツを
40+ /// 読み込むことができます。base.Initialize を呼び出すと、使用するすべての
41+ /// コンポーネントが列挙されるとともに、初期化されます。
42+ /// </summary>
43+ protected override void Initialize()
44+ {
45+ // TODO: ここに初期化ロジックを追加します。
46+
47+ base.Initialize();
48+ }
49+
50+ /// <summary>
51+ /// LoadContent はゲームごとに 1 回呼び出され、ここですべてのコンテンツを
52+ /// 読み込みます。
53+ /// </summary>
54+ protected override void LoadContent()
55+ {
56+ //モデルとモーションをロード
57+ model = MMDXCore.Instance.LoadModel("Miku", Content);
58+ motion1 = MMDXCore.Instance.LoadMotion("LeftHand", Content);
59+ motion2 = MMDXCore.Instance.LoadMotion("RightBye", Content);
60+ //モーションをセット
61+ //UpdateWhenStoppedは再生停止中もトラック中のモーションを適用する
62+ //MMDMotionTrackOptions.Noneだと、再生停止中はモーショントラックを適用しない
63+ //ExtendedModeはキーフレームが無い再生位置でも最後のキーフレームを参照する
64+ model.AnimationPlayer.AddMotion("LeftHand", motion1, MMDMotionTrackOptions.UpdateWhenStopped | MMDMotionTrackOptions.ExtendedMode);
65+ model.AnimationPlayer.AddMotion("RightBye", motion2, MMDMotionTrackOptions.UpdateWhenStopped | MMDMotionTrackOptions.ExtendedMode);
66+ //最初のブレンディングはLeftHandの方を100%にする
67+ model.AnimationPlayer["LeftHand"].BlendingFactor = 1f;//最初から1なのだが、分り易くするために代入
68+ model.AnimationPlayer["RightBye"].BlendingFactor = 0f;//ブレンディングファクターを0にする。
69+ //両方ループ再生する
70+ model.AnimationPlayer["LeftHand"].Start(true);
71+ model.AnimationPlayer["RightBye"].Start(true);
72+ //ExtendedModeを指定する理由
73+ //モーションブレンディングは2つ以上のモーションを重ねあわせて行うもの
74+ //何もフレームがない場合は、ブレンディングを行わない
75+ //一方、フレームがあるとブレンディングを行うが、途中でフレームが終わるボーンは、そこでそのボーンのフレームが無くなるため、
76+ //途中でブレンディングが非連続的にそのボーンだけ無くなり、意図しない動作をすることがある。
77+ }
78+
79+ /// <summary>
80+ /// UnloadContent はゲームごとに 1 回呼び出され、ここですべてのコンテンツを
81+ /// アンロードします。
82+ /// </summary>
83+ protected override void UnloadContent()
84+ {
85+ // TODO: ここで ContentManager 以外のすべてのコンテンツをアンロードします。
86+ }
87+
88+ /// <summary>
89+ /// ワールドの更新、衝突判定、入力値の取得、オーディオの再生などの
90+ /// ゲーム ロジックを、実行します。
91+ /// </summary>
92+ /// <param name="gameTime">ゲームの瞬間的なタイミング情報</param>
93+ protected override void Update(GameTime gameTime)
94+ {
95+ // ゲームの終了条件をチェックします。
96+ if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
97+ this.Exit();
98+ //Enterキーでブレンディングファクター変化値を設定
99+ if (Keyboard.GetState().IsKeyDown(Keys.Enter) && FactorVelocity == 0m)
100+ {
101+ if (FactorPosition == 0m)
102+ FactorVelocity = 0.1m;
103+ else if (FactorPosition == 1m)
104+ FactorVelocity = -0.1m;
105+ }
106+ //ブレンディングファクター値変化中
107+ if (FactorVelocity != 0m)
108+ {
109+ FactorPosition += FactorVelocity;
110+ if (FactorPosition <= 0m)
111+ {
112+ FactorPosition = 0m;
113+ FactorVelocity = 0m;
114+ }
115+ else if (FactorPosition >= 1m)
116+ {
117+ FactorPosition = 1m;
118+ FactorVelocity = 0m;
119+ }
120+ //ブレンディングファクターを設定し、モーションの切り替えをスムースに行う
121+ model.AnimationPlayer["LeftHand"].BlendingFactor = (float)(1m - FactorPosition);
122+ model.AnimationPlayer["RightBye"].BlendingFactor = (float)FactorPosition;
123+ }
124+
125+ MMDXCore.Instance.Update((float)gameTime.ElapsedGameTime.TotalSeconds);
126+ // TODO: ここにゲームのアップデート ロジックを追加します。
127+
128+ base.Update(gameTime);
129+ }
130+
131+ /// <summary>
132+ /// ゲームが自身を描画するためのメソッドです。
133+ /// </summary>
134+ /// <param name="gameTime">ゲームの瞬間的なタイミング情報</param>
135+ protected override void Draw(GameTime gameTime)
136+ {
137+ GraphicsDevice.Clear(Color.CornflowerBlue);
138+ //モデルの描画
139+ model.Draw();
140+
141+ base.Draw(gameTime);
142+ }
143+ protected override void Dispose(bool disposing)
144+ {
145+ model.Dispose();
146+ //MMDの破棄処理を実行
147+ MMDXCore.Instance.Dispose();
148+ base.Dispose(disposing);
149+ }
150+ }
151+}
--- trunk/MikuMikuDanceCore/Model/MMDFaceManager.cs (revision 903)
+++ trunk/MikuMikuDanceCore/Model/MMDFaceManager.cs (revision 904)
@@ -54,10 +54,17 @@
5454 {
5555 this.vertData = vertData;
5656 this.faceRates = new Dictionary<string, float[]>();
57- foreach (var it in vertData)
58- if (it.Key != "base")
59- this.faceRates.Add(it.Key, new float[2] { 0.0f, 0.0f });
60- updateVerts = new Dictionary<int, Vector3>(vertData["base"].Length);
57+ if (vertData != null && vertData.ContainsKey("base"))
58+ {
59+ foreach (var it in vertData)
60+ if (it.Key != "base")
61+ this.faceRates.Add(it.Key, new float[2] { 0.0f, 0.0f });
62+ updateVerts = new Dictionary<int, Vector3>(vertData["base"].Length);
63+ }
64+ else
65+ {
66+ updateVerts = new Dictionary<int, Vector3>();
67+ }
6168 }
6269 /// <summary>
6370 /// 表情適用割合の取得/設定
@@ -138,6 +145,8 @@
138145 /// <param name="indices">PMD→MMDXの頂点変換マップ</param>
139146 public static void ApplyToVertex(MMDFaceManager faceManager, MMDVertexNm[] vert, Dictionary<long,int[]> indices = null)
140147 {
148+ if (!faceManager.vertData.ContainsKey("base"))
149+ return;
141150 if (MMDCore.Instance.OpaqueData.ContainsKey("StrictFaceVert"))
142151 {
143152 foreach (var skinvert in faceManager.vertData["base"])
@@ -178,51 +187,7 @@
178187 }
179188 }
180189 }
181- /*if (indices == null)
182- {
183-
184-
185- //Parallel.ForEach(faceManager.vertData, (it) =>
186- foreach(var it in faceManager.vertData)
187- {
188- //baseで初期化
189- vert[it.Key].Position = it.Value[0].vector;
190- for (int j = 1; j < it.Value.Length; ++j)
191- {
192- if (faceManager.faceRates[it.Value[j].FaceName] > 0)
193- {
194- Vector3 temp;
195- Vector3.Multiply(ref it.Value[j].vector, faceManager.faceRates[it.Value[j].FaceName], out temp);
196- vert[it.Key].Position += temp;
197- }
198- }
199-
200- }//);
201- }
202- else
203- {
204- //Parallel.ForEach(faceManager.vertData, (it) =>
205- foreach(var it in faceManager.vertData)
206- {
207- if (indices.ContainsKey(it.Key))
208- {
209- foreach (var i in indices[it.Key])
210- {
211- //baseで初期化
212- vert[i].Position = it.Value[0].vector;
213- for (int j = 1; j < it.Value.Length; ++j)
214- {
215- if (faceManager.faceRates[it.Value[j].FaceName] > 0)
216- {
217- Vector3 temp;
218- Vector3.Multiply(ref it.Value[j].vector, faceManager.faceRates[it.Value[j].FaceName], out temp);
219- vert[i].Position += temp;
220- }
221- }
222- }
223- }
224- }//);
225- }*/
190+
226191 }
227192 #endif
228193
--- trunk/MikuMikuDanceCore/Motion/AnimationPlayer.cs (revision 903)
+++ trunk/MikuMikuDanceCore/Motion/AnimationPlayer.cs (revision 904)
@@ -123,6 +123,8 @@
123123 foreach (var track in motionTracks)
124124 {
125125 track.Value.Update(elapsedSeconds, track.Key);
126+ if (track.Value.SubPoses.Count < 2)
127+ throw new NotImplementedException();
126128 foreach (var subpose in track.Value.SubPoses)
127129 {
128130 SQTTransform pose1, pose2, sub = subpose.Value, result;
--- trunk/MikuMikuDanceCore/Motion/MMDMotionTrackOptions.cs (revision 903)
+++ trunk/MikuMikuDanceCore/Motion/MMDMotionTrackOptions.cs (revision 904)
@@ -16,5 +16,9 @@
1616 /// 停止中もボーンや表情を更新する
1717 /// </summary>
1818 UpdateWhenStopped = 0x1,
19+ /// <summary>
20+ /// 現在の再生位置間にキーフレームが無くなったボーンも、最後のフレームのままだとして、再生を継続する
21+ /// </summary>
22+ ExtendedMode = 0x2,
1923 }
2024 }
--- trunk/MikuMikuDanceCore/Motion/MMDMotionTrack.cs (revision 903)
+++ trunk/MikuMikuDanceCore/Motion/MMDMotionTrack.cs (revision 904)
@@ -181,8 +181,10 @@
181181 {
182182 //カーソル位置の更新
183183 int CursorPos = bonePos[frameList.Key];
184- if (!bUserChangeFrame && ((bReverse && CursorPos == 0) || (!bReverse && CursorPos == frameList.Value.Count)))
184+ if (!bUserChangeFrame && ((bReverse && CursorPos == 0) || (!bReverse && CursorPos == frameList.Value.Count)) && (Options | MMDMotionTrackOptions.ExtendedMode) == 0)
185+ {
185186 continue;//このボーンの再生終わり
187+ }
186188 if (!bReverse)
187189 {
188190 for (; CursorPos < frameList.Value.Count && frameList.Value[CursorPos].FrameNo < m_NowFrame; ++CursorPos) ;
@@ -297,7 +299,7 @@
297299 {
298300 if (!bReverse)
299301 {
300- while (m_NowFrame >= m_MaxFrame)
302+ while (m_NowFrame >= m_MaxFrame && m_MaxFrame != 0)
301303 m_NowFrame -= m_MaxFrame;
302304 //ボーンの更新
303305 foreach (var frameList in boneFrames)
@@ -307,7 +309,7 @@
307309 }
308310 else
309311 {
310- while (m_NowFrame <= 0)
312+ while (m_NowFrame <= 0 && m_MaxFrame != 0)
311313 m_NowFrame += m_MaxFrame;
312314 //ボーンの更新
313315 foreach (var frameList in boneFrames)
Show on old repository browser