From 85debbbcae1a77b0a7a00550d42cedb5b0e5b447 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 24 Sep 2013 02:02:58 +0900 Subject: [PATCH 01/37] =?UTF-8?q?PMDLoaderWindow:=E9=9D=9E=E6=8E=A8?= =?UTF-8?q?=E5=A5=A8=E9=96=A2=E6=95=B0=E3=81=AE=E5=BB=83=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/PMDLoaderWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index 861c770..cdb797a 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -31,7 +31,7 @@ public PMDLoaderWindow() } void OnGUI() { - pmdFile = EditorGUILayout.ObjectField("PMD File" , pmdFile, typeof(Object)); + pmdFile = EditorGUILayout.ObjectField("PMD File" , pmdFile, typeof(Object), false); // シェーダの種類 shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); From 59d11fc4e245b28663e2795d45b5c6a08fd7dcca Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 15:41:26 +0900 Subject: [PATCH 02/37] =?UTF-8?q?=E8=82=98=E3=81=8C=E7=9C=9F=E3=81=A3?= =?UTF-8?q?=E7=9B=B4=E3=81=90=E3=81=A7=E3=81=AF=E3=81=AA=E3=81=8F=E6=9B=B2?= =?UTF-8?q?=E3=81=8C=E3=81=A3=E3=81=A6=E3=81=84=E3=82=8B=E3=83=A2=E3=83=87?= =?UTF-8?q?=E3=83=AB=E3=82=92=E7=A2=BA=E8=AA=8D=EF=BC=88=E5=88=9D=E9=9F=B3?= =?UTF-8?q?=E3=83=9F=E3=82=AFXS=EF=BC=89=20=E3=81=A9=E3=81=86=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=8B=E3=81=AF=E6=82=A9=E3=82=93=E3=81=A7=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/AvatarSettingScript.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index 66e5455..f5c51e2 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -98,6 +98,10 @@ void SetRequirePose(Transform transform) case "右肩": //Tポーズにする為に腕を持ち上げる transform.localRotation = Quaternion.Euler(0.0f, 0.0f, -9.0f); break; + case "左ひじ": //稀に肘が曲がっていることがあるので矯正 + break; + case "右ひじ": //上に同様に肘を矯正 + break; case "左腕": //Tポーズにする為に腕を持ち上げる transform.localRotation = Quaternion.Euler(0.0f, 0.0f, 27.0f); break; From 2c413d6cfba3daf1ee7e114f4c1d9f145b12886d Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 17:07:39 +0900 Subject: [PATCH 03/37] =?UTF-8?q?=E8=85=95=E3=82=92=E6=B0=B4=E5=B9=B3?= =?UTF-8?q?=E3=81=AB=E3=81=99=E3=82=8B=E3=81=9F=E3=82=81=E3=81=AE=E9=96=A2?= =?UTF-8?q?=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MMDLoader/Private/AvatarSettingScript.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index f5c51e2..56bbb67 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -85,6 +85,35 @@ void SetRequirePose() } } + /// + /// 親子関係を見てボーンを水平にする + /// + /// 対象のボーン + /// Z軸のみを回転させるQuaternion + Quaternion ResetHorizontalPose(Transform transform) + { + // 最も子オブジェクトの多いもの != 剛体ボーン + var children = new List(transform.childCount); + for (int i = 0; i < transform.childCount; i++) + children.Add(transform.GetChild(i)); + int child_index = children.Max(x => x.childCount); + var child_transform = transform.GetChild(child_index); + + // ボーンの向きを取得 + var bone_vector = child_transform.position - transform.position; + bone_vector.z = 0f; // 平面化 + bone_vector.Normalize(); + + // 平面化した正規化ベクトルと単位ベクトルを比較して,角度を取得する + Vector3 normalized_vector = bone_vector.x >= 0 ? Vector3.right : Vector3.left; + float cos_value = Vector3.Dot(bone_vector, normalized_vector); + float theta = Mathf.Acos(cos_value) * Mathf.Rad2Deg; + + theta = bone_vector.x >= 0 ? theta : -theta; // ボーンの向きによって回転方向が違う + + return Quaternion.Euler(0f, 0f, theta); + } + /// /// 生成済みのボーンをUnity推奨ポーズに設定 /// From 9d4509ecc3e8dacdb72560997d4efd3d56dfb8d6 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 17:07:39 +0900 Subject: [PATCH 04/37] =?UTF-8?q?=E8=85=95=E3=82=92=E6=B0=B4=E5=B9=B3?= =?UTF-8?q?=E3=81=AB=E3=81=99=E3=82=8B=E3=81=9F=E3=82=81=E3=81=AE=E9=96=A2?= =?UTF-8?q?=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0=20=09.git/CHERRY=5FPICK=5F?= =?UTF-8?q?HEAD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 23fc641e758ba7d0352b20610f58d4a8415c493d Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 21:41:28 +0900 Subject: [PATCH 05/37] =?UTF-8?q?=E5=AD=90=E3=83=9C=E3=83=BC=E3=83=B3?= =?UTF-8?q?=E3=82=92=E9=81=B8=E3=81=B3=E5=87=BA=E3=81=99=E5=87=A6=E7=90=86?= =?UTF-8?q?=E3=82=92=E9=96=A2=E6=95=B0=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/AvatarSettingScript.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index 56bbb67..214c70a 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -86,19 +86,26 @@ void SetRequirePose() } /// - /// 親子関係を見てボーンを水平にする + /// 対象のボーンの中からより深く枝分かれする子ボーンを選び出す /// /// 対象のボーン - /// Z軸のみを回転させるQuaternion - Quaternion ResetHorizontalPose(Transform transform) + /// さらに枝分かれする子ボーン + Transform SelectBranchedChildWhereManyChildren(Transform transform) { - // 最も子オブジェクトの多いもの != 剛体ボーン var children = new List(transform.childCount); for (int i = 0; i < transform.childCount; i++) children.Add(transform.GetChild(i)); int child_index = children.Max(x => x.childCount); - var child_transform = transform.GetChild(child_index); + return transform.GetChild(child_index); + } + /// + /// 親子関係を見てボーンを水平にする + /// + /// 対象のボーン + /// Z軸のみを回転させるQuaternion + Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) + { // ボーンの向きを取得 var bone_vector = child_transform.position - transform.position; bone_vector.z = 0f; // 平面化 From a781768b50d98fc615c942ef28404b6c0a0447e4 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 22:31:02 +0900 Subject: [PATCH 06/37] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92?= =?UTF-8?q?=E5=B0=91=E3=81=97=E3=81=A0=E3=81=91=E3=82=B9=E3=83=83=E3=82=AD?= =?UTF-8?q?=E3=83=AA=E3=81=95=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MMDLoader/Private/AvatarSettingScript.cs | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index 214c70a..dabe67e 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -87,16 +87,18 @@ void SetRequirePose() /// /// 対象のボーンの中からより深く枝分かれする子ボーンを選び出す + /// 剛体用ボーンじゃないきちんとしたボーンを選び出すために使う /// /// 対象のボーン /// さらに枝分かれする子ボーン Transform SelectBranchedChildWhereManyChildren(Transform transform) { - var children = new List(transform.childCount); + Transform[] children = new Transform[transform.childCount]; + if (children.Length <= 0) Debug.LogError(transform.name + "の子がないので落ちるのです!"); for (int i = 0; i < transform.childCount; i++) - children.Add(transform.GetChild(i)); - int child_index = children.Max(x => x.childCount); - return transform.GetChild(child_index); + children[i] = transform.GetChild(i); + int max = children.Max(x => x.childCount); + return children.Where(x => x.childCount == max).ToArray()[0]; } /// @@ -121,6 +123,20 @@ Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) return Quaternion.Euler(0f, 0f, theta); } + /// + /// 腕全体を平行にする処理 + /// + /// 肩ボーン + void StartResettingHorizontal(Transform shoulder) + { + var arm = SelectBranchedChildWhereManyChildren(shoulder); + var hinge = SelectBranchedChildWhereManyChildren(arm); + var wrist = SelectBranchedChildWhereManyChildren(hinge); + shoulder.transform.localRotation = ResetHorizontalPose(shoulder, arm); + arm.transform.localRotation = ResetHorizontalPose(arm, hinge); + hinge.transform.localRotation = ResetHorizontalPose(hinge, wrist); + } + /// /// 生成済みのボーンをUnity推奨ポーズに設定 /// @@ -128,21 +144,9 @@ Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) void SetRequirePose(Transform transform) { switch (transform.name) { - case "左肩": //Tポーズにする為に腕を持ち上げる - transform.localRotation = Quaternion.Euler(0.0f, 0.0f, 9.0f); - break; + case "左肩": goto case "右肩"; case "右肩": //Tポーズにする為に腕を持ち上げる - transform.localRotation = Quaternion.Euler(0.0f, 0.0f, -9.0f); - break; - case "左ひじ": //稀に肘が曲がっていることがあるので矯正 - break; - case "右ひじ": //上に同様に肘を矯正 - break; - case "左腕": //Tポーズにする為に腕を持ち上げる - transform.localRotation = Quaternion.Euler(0.0f, 0.0f, 27.0f); - break; - case "右腕": //Tポーズにする為に腕を持ち上げる - transform.localRotation = Quaternion.Euler(0.0f, 0.0f, -27.0f); + StartResettingHorizontal(transform); break; case "腰": goto case "センター"; case "センター": From 5c8b853a567696944bb8309b1a0f559ca509d691 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 22:50:33 +0900 Subject: [PATCH 07/37] =?UTF-8?q?Use=20mecanim=E3=81=8CON=E3=81=AB?= =?UTF-8?q?=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=8F=E3=82=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=EF=BC=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Config/Config.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Editor/Config/Config.cs b/Editor/Config/Config.cs index ce958bf..9c0adfe 100644 --- a/Editor/Config/Config.cs +++ b/Editor/Config/Config.cs @@ -77,7 +77,6 @@ public static Config LoadAndCreate() AssetDatabase.CreateAsset(config, path); EditorUtility.SetDirty(config); } - Debug.Log(config); return config; } } @@ -131,7 +130,7 @@ public override void OnGUI() { shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); - use_mecanim = false; + use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); // ここfalseになってたけど理由があるのかわからない use_ik = EditorGUILayout.Toggle("Use IK", use_ik); is_pmx_base_import = EditorGUILayout.Toggle("Use PMX Base Import", is_pmx_base_import); } From 9041abe365a0dfaaac3a9b9f2a632ce87975b91a Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 29 Sep 2013 22:50:52 +0900 Subject: [PATCH 08/37] =?UTF-8?q?=E3=83=97=E3=83=A9=E3=82=B9=E3=81=A8?= =?UTF-8?q?=E3=83=9E=E3=82=A4=E3=83=8A=E3=82=B9=E9=96=93=E9=81=95=E3=81=88?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/AvatarSettingScript.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index dabe67e..33bef1f 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -98,7 +98,7 @@ Transform SelectBranchedChildWhereManyChildren(Transform transform) for (int i = 0; i < transform.childCount; i++) children[i] = transform.GetChild(i); int max = children.Max(x => x.childCount); - return children.Where(x => x.childCount == max).ToArray()[0]; + return children.Where(x => x.childCount == max).First(); } /// @@ -118,7 +118,7 @@ Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) float cos_value = Vector3.Dot(bone_vector, normalized_vector); float theta = Mathf.Acos(cos_value) * Mathf.Rad2Deg; - theta = bone_vector.x >= 0 ? theta : -theta; // ボーンの向きによって回転方向が違う + theta = bone_vector.x >= 0 ? -theta : theta; // ボーンの向きによって回転方向が違う return Quaternion.Euler(0f, 0f, theta); } From cec7bc48ca202b43d416be3fd2ba2c1ee8bb28ac Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Tue, 22 Oct 2013 02:09:55 +0900 Subject: [PATCH 09/37] Update PMDLoaderWindow.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit メニューバーに表示するアレを変更 --- Editor/MMDLoader/PMDLoaderWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index cdb797a..154e652 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -13,7 +13,7 @@ public class PMDLoaderWindow : EditorWindow { float scale = 0.085f; bool is_pmx_base_import = false; - [MenuItem("Plugins/MMD Loader/PMD Loader")] + [MenuItem("MMD for Unity/PMD Loader")] static void Init() { var window = (PMDLoaderWindow)EditorWindow.GetWindow(true, "PMDLoader"); window.Show(); From 906e4b3ce5b11322f679f48e14131592b371ee10 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Tue, 22 Oct 2013 02:10:20 +0900 Subject: [PATCH 10/37] Update VMDLoaderWindow.cs --- Editor/MMDLoader/VMDLoaderWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/MMDLoader/VMDLoaderWindow.cs b/Editor/MMDLoader/VMDLoaderWindow.cs index 16c3aa4..56dca50 100644 --- a/Editor/MMDLoader/VMDLoaderWindow.cs +++ b/Editor/MMDLoader/VMDLoaderWindow.cs @@ -8,7 +8,7 @@ public class VMDLoaderWindow : EditorWindow { bool createAnimationFile; int interpolationQuality; - [MenuItem ("Plugins/MMD Loader/VMD Loader")] + [MenuItem ("MMD for Unity/VMD Loader")] static void Init() { var window = (VMDLoaderWindow)EditorWindow.GetWindow(true, "VMDLoader"); window.Show(); From ccf3323c78b1c9b789b5f3695f3f1b514113f473 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Tue, 22 Oct 2013 02:10:52 +0900 Subject: [PATCH 11/37] Update XFileImporterWindow.cs --- Editor/XFileImporter/XFileImporterWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/XFileImporter/XFileImporterWindow.cs b/Editor/XFileImporter/XFileImporterWindow.cs index 5dd09ce..38af9c1 100644 --- a/Editor/XFileImporter/XFileImporterWindow.cs +++ b/Editor/XFileImporter/XFileImporterWindow.cs @@ -5,7 +5,7 @@ public class XFileImporterWindow : EditorWindow { Object xFile = null; - [MenuItem ("Plugins/XFile Importer")] + [MenuItem ("MMD for Unity/XFile Importer")] static void Init() { var window = (XFileImporterWindow)EditorWindow.GetWindow(true, "XFile Importer"); window.Show(); From 6360298ca7f543f4bd64c770de11ae93fc089279 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Thu, 24 Oct 2013 02:48:01 +0900 Subject: [PATCH 12/37] add git ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6425e29..da4ae55 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.csproj *.unityproj *.sln +*.asset \ No newline at end of file From 87c4e2efb5503eaccb2090b967bf87aa7953ded4 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Sun, 3 Nov 2013 19:21:58 +0900 Subject: [PATCH 13/37] Update ConfigWindow.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configだけ残ってて気になったので修正 --- Editor/Config/ConfigWindow.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/Config/ConfigWindow.cs b/Editor/Config/ConfigWindow.cs index d7413bb..08fa9b3 100644 --- a/Editor/Config/ConfigWindow.cs +++ b/Editor/Config/ConfigWindow.cs @@ -8,7 +8,7 @@ public class ConfigWindow : EditorWindow private static Config config; private static string path; - [MenuItem("Plugins/MMD Loader/Config")] + [MenuItem("MMD for Unity/Config")] public static void Init() { GetWindow("MFU Config"); @@ -50,4 +50,4 @@ void OnGUI() } } -} \ No newline at end of file +} From f61f8d5f6cfa5a1b410ec124ffd46da47013c3c3 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Mon, 4 Nov 2013 00:22:59 +0900 Subject: [PATCH 14/37] imifumei --- Editor/Config/Config.asset | Bin 4192 -> 4196 bytes tutorial.md | 137 +++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 tutorial.md diff --git a/Editor/Config/Config.asset b/Editor/Config/Config.asset index d48dc4bd987c93615896c2a1844fcb1869b0fb03..2e136a5eb69948812e392b492b7eab31fa261b16 100644 GIT binary patch delta 189 zcmaE$@I*nHfq`uk1A{;c0|NsmkOoo=3?_O;dPZr68>LUPi1GmWKt*7{2qHUxIwt>S zStOU1lb=|^P@J5YlghvXlu!W40s&YR$K>g(%8ZJWH?l}gzRD`ks5JR2t0AK@kS{#h zicOYLWpV_YvJ%MF|3FX#)3)enLWF{^yTiVxYkT@qO$}=iXmSi(zR08saC&#hLGAd85VN+I20BZUV1Vum^ qY(nq18)eH&1st}XdMMG8vSGpI18feQlP|ETOcDs0*uVm^5exv4VJ9yD diff --git a/tutorial.md b/tutorial.md new file mode 100644 index 0000000..f52187b --- /dev/null +++ b/tutorial.md @@ -0,0 +1,137 @@ +--- +layout: page +title: Tutorial +--- + +MMD for Unityの使い方 +======================== + +## MikuMikuDanceの基礎 +MikuMikuDanceとは,樋口優氏が開発した3DCGアニメーションソフトの1種です. +3DCGの初音ミクが踊っている動画を作成するために作られたフリーソフトです. + +MikuMikuDanceではニコニコ動画やYoutubeを中心に,多くの動画が公開されています. +また,有志によって多くのモデルデータやモーションデータが公開されているため, +初音ミクの他に色々なキャラクターが踊る動画を作ることができます. + +### データの基本 +MikuMikuDanceでは,3種類のデータを扱うことができます. +シーンデータを扱うための **PMMファイル** , +モデルデータを扱うための **PMD/PMXファイル** , +モーションデータを扱うための **VMDファイル** の3種類です. + +MikuMikuDanceでは,キャラクターを3DCGのデータとして扱っています. +そのデータが **PMD/PMX** ファイルです. +また,キャラクターを踊らせた時のデータ(モーション)が **VMDファイル** です. + +MikuMikuDanceではモデルデータ(キャラクター)をいくつか読み込み, +それぞれ踊りや振り付けなどを編集します. +この時,編集している場面を **シーン** と呼びます. +このシーンを保存するためのデータが **PMMファイル** です. + +VMDファイルとPMMファイルの違いは, +PMMファイルはMikuMikuDanceで編集している場面全体を保存するためのデータなのに対し, +VMDファイルはキャラクター1体だけのモーションを保存するためのデータとなっていることです. +このことから,場面全体を保存したい場合はPMM,モーションを公開したい場合はVMDになっています. + +### モーションを保存する +MikuMikuDanceのキャラクターでゲームを作るのに, +ダウンロードしたモーションだけでは足りないこともあります. +その時はMikuMikuDanceでモーションを自作し, +モーションデータをMMD for Unityで読み込みます. + +自作したモーションは, +保存したいキーフレームを選択してから「ファイル-モーションデータを保存」で保存することができます. +キーフレームが選択されていないと正しく保存されないので注意して下さい. +キーフレームを選択する方法はいくつかありますが, +その中でも一般的な方法を紹介します. + +![範囲選択まわり](images/all-frame.png) + +まず,フレーム操作下部のプルダウンメニューから,「全フレーム」を選択して下さい. +次に,隣のテキストボックスに保存したいフレーム数の範囲を入力し, +範囲選択ボタンをクリックします. +これで指定範囲のキーフレームが選択状態になります. + +他にも,プルダウンメニューから「選択ボーン」を選ぶことで, +選択したボーンだけを保存することのできる機能もあります. + +## MMD for Unityのインストール +MMD for Unityでは,パッケージではなく圧縮ファイルで提供しています. +ページ上部のZIPボタンから圧縮ファイルをダウンロードすることができます. +ダウンロードした圧縮ファイルを解凍すると,mmd-for-unityというフォルダが現れます. +このフォルダがMMD for Unityとなります. + +MMD for UnityのフォルダをUnityのProjectに置くだけでインストールが完了します. + +## MMD for Unityの使い方 +MMD for Unityでは,PMD/PMXファイルの読み込みと,VMDファイルの読み込みができます. +それぞれの操作方法について説明します. + +### PMD Loader +PMD Loaderとは,PMDファイルを読み込むための機能です. +MikuMikuDanceのモデルデータをUnityにインポートします. +PMD LoaderはメニューバーのMMD for Unity(旧バージョンではPlugins), +もしくはPMDファイルをクリックし,Inspectorを操作することで利用できます. + +![メニューバーから呼び出したPMD Loader](images/pmd-loader.png) + +まず,PMD Loaderを起動する前にモデルデータをProjectに追加する必要があります. +モデルデータが入っているフォルダごと,Projectへドラッグ&ドロップしてください. +なお,このフォルダの中身を変更したり移動すると読み込みに失敗します. + +PMD Fileには,MikuMikuDanceのPMDファイルをドラッグ&ドロップしてください. +PMDファイルをドラッグ&ドロップすると,Convertボタンが現れるのでクリックすると読み込みが始まります. +読み込みが完了するとProjectにPrefabが追加されます. +また,読み込んだキャラクターがHierarchyに追加されるので,成功の目安にしてください. + +それぞれの項目の意味について説明します. + +Shader Typeは描画するのに使われるシェーダの種類を選択します.デフォルトはMMDShaderです. +他にもいくつかシェーダに種類があります. + +Rigidbodyは剛体を利用したいときにチェックします. +剛体を利用することで,物理エンジンによって髪の毛やスカートの揺れ等が表現できるようになります. +(ただし,モデルデータに剛体の情報がある場合のみ) + +Use Mecanimをチェックすると,Mecanimが利用できるように調整します. + +Use IKは,IKを利用したいときにチェックします. +通常,胴体や腕などのボーンはFK(Forward Kinematics,順運動学)と呼ばれる方法でアニメーションされます. +例えば,肩,肘,手首などのように,根本から末端の順番でアニメーションさせる仕組みです. +一方,IK(Inverce Kinematics,逆運動学)は, +手首の位置だけ先に決めておいて,肘と肩の角度は後から決めるような仕組みになっています. +通常,MikuMikuDanceではこのIKが多用されているので, +完全に動かしたい場合はオンにすることを推奨します. + +Scaleは読み込んだモデルの大きさです. +UnityとMikuMikuDanceでは,大きさの単位が異なるため, +MikuMikuDanceからUnityへ大きさを揃える必要があります. +Originalボタンを押すと,1メートルを基準とした大きさに揃えられます. +1.0ボタンを押すと,MikuMikuDanceを基準とした大きさに揃えられます. +Use PMX Base Importは,PMXファイルを読み込みたいときにチェックします. + +### VMD Loader +VMD Loaderとは,VMDファイルを読み込むための機能です. +MikuMikuDanceのモーションデータをUnityにインポートします. +VMD LoaderはメニューバーのMMD for Unity(旧バージョンではPlugins), +もしくはVMDファイルをクリックし,Inspectorを操作することで利用できます. + +![メニューバーから呼び出したVMD Loader](images/vmd-loader.png) + +PMD Prefabには,PMD Loaderで生成されたPrefabをドラッグ&ドロップします. +また,VMD Fileには,VMDファイルをドラッグ&ドロップしてください. +VMD Loaderでは,PMD Prefabにモーションデータを流し込み,アニメーションクリップを生成します. +この2つの項目を埋めることでConvertボタンが出現します. +クリックすると変換が始まります. + +それぞれの項目の意味について説明します. + +Create Assetをチェックすると,アニメーションクリップをPrefabの中だけでなく,アセットファイルとして出力します. + +Interpolation Qualityは,線形補間の品質です. +UnityとMikuMikuDanceでは線形補間の方法が異なります. +そのため,擬似的にMikuMikuDanceの線形補間を再現するため, +アニメーションの中にキーフレームをいくつか打つ方式を取っています. +Interpolation Qualityを高くするほど多くのキーフレームを打ちますが, +それだけデータ量が多くなるので注意してください. \ No newline at end of file From de5216cd8e0a77693e26358cac85d6ab881b7620 Mon Sep 17 00:00:00 2001 From: Eiichi Takebuchi Date: Mon, 11 Nov 2013 00:31:30 +0900 Subject: [PATCH 15/37] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 355e1bf..6caca77 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ mmd-for-unity ============= -MikuMikuDance for Unity + +[MikuMikuDance for Unity 公式ページ](http://mmd-for-unity-proj.github.io/mmd-for-unity/) From d768dd3dd00b6ffcaf439fe2d8dc0382b62a3a15 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 16 Nov 2013 10:06:56 +0900 Subject: [PATCH 16/37] =?UTF-8?q?3.5=E4=BB=A5=E5=89=8D(=E5=90=AB=E3=82=80)?= =?UTF-8?q?=E3=81=AE=E5=AF=BE=E5=BF=9C=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=91=E3=82=A4=E3=83=AB=E5=88=86=E5=B2=90=E3=82=92=E5=BB=83?= =?UTF-8?q?=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Inspector/PMDInspector.cs | 8 +++----- Editor/MMDLoader/PMDLoaderWindow.cs | 6 +++--- Editor/MMDLoader/Private/AvatarSettingScript.cs | 4 ++-- Editor/MMDLoader/Private/MMDConverter.cs | 11 ++++------- Editor/MMDLoader/Private/PMXConverter.cs | 11 ++++------- 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/Editor/Inspector/PMDInspector.cs b/Editor/Inspector/PMDInspector.cs index 51aff24..84e5afb 100644 --- a/Editor/Inspector/PMDInspector.cs +++ b/Editor/Inspector/PMDInspector.cs @@ -4,7 +4,6 @@ using MMD.PMD; using System.IO; -#if !(UNITY_3_5 || UNITY_3_4 || UNITY_3_3) namespace MMD { [CustomEditor(typeof(PMDScriptableObject))] @@ -65,13 +64,13 @@ public override void OnInspectorGUI() rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); // Mecanimを使うかどうか -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); -#else //UNITY_4_2 +#else GUI.enabled = false; use_mecanim = EditorGUILayout.Toggle("Use Mecanim", false); GUI.enabled = !EditorApplication.isPlaying; -#endif //UNITY_4_2 +#endif // IKを使うかどうか use_ik = EditorGUILayout.Toggle("Use IK", use_ik); @@ -129,4 +128,3 @@ public override void OnInspectorGUI() } } } -#endif diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index 154e652..5f68dd2 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -40,14 +40,14 @@ void OnGUI() { rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); // Mecanimを使うかどうか -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); -#else //UNITY_4_2 +#else bool old_gui_enabled = GUI.enabled; GUI.enabled = false; use_mecanim = EditorGUILayout.Toggle("Use Mecanim", false); GUI.enabled = old_gui_enabled; -#endif //UNITY_4_2 +#endif // IKを使うかどうか use_ik = EditorGUILayout.Toggle("Use IK", use_ik); diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index 33bef1f..3726b9e 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -1,4 +1,4 @@ -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 using UnityEngine; using UnityEditor; @@ -316,4 +316,4 @@ void DisableIk() Animator animator_ = null; } -#endif //UNITY_4_2 +#endif diff --git a/Editor/MMDLoader/Private/MMDConverter.cs b/Editor/MMDLoader/Private/MMDConverter.cs index 810af44..9ffca15 100644 --- a/Editor/MMDLoader/Private/MMDConverter.cs +++ b/Editor/MMDLoader/Private/MMDConverter.cs @@ -89,7 +89,7 @@ private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, b } // Mecanim設定 -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 if (use_mecanim_) { AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); avatar_setting.SettingAvatar(); @@ -101,9 +101,9 @@ private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, b } else { root_game_object_.AddComponent(); // アニメーション追加 } -#else //UNITY_4_2 +#else root_game_object_.AddComponent(); // アニメーション追加 -#endif //UNITY_4_2 +#endif return root_game_object_; } @@ -200,11 +200,8 @@ bool IsTransparentMaterial(PMD.PMDFormat.Material model_material, Texture2D text bool result = false; result = result || (model_material.alpha < 0.98f); //0.98f以上は不透明と見做す(0.98fに影生成情報を埋め込んでいる為) if (null != texture) { -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 result = result || texture.alphaIsTransparency; -#else - // TODO: 上記のif内の代替コードが必要です - //result = result; #endif } return result; diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 7ebfd65..936ba6b 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -79,7 +79,7 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool } // Mecanim設定 -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 if (use_mecanim_) { //アニメーター追加 AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); @@ -92,9 +92,9 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool } else { root_game_object_.AddComponent(); // アニメーション追加 } -#else //UNITY_4_2 +#else root_game_object_.AddComponent(); // アニメーション追加 -#endif //UNITY_4_2 +#endif return root_game_object_; } @@ -487,11 +487,8 @@ bool IsTransparentMaterial(PMXFormat.Material material, Texture2D texture) { bool result = false; result = result || (material.diffuse_color.a < 1.0f); if (null != texture) { -#if UNITY_4_2 +#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 result = result || texture.alphaIsTransparency; -#else - // TODO: 上記if内の代替コード必須です - // result = result; #endif } return result; From 31525c6a44bdafefa5e1b6c6797bc1dd49021627 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 16 Nov 2013 10:13:54 +0900 Subject: [PATCH 17/37] =?UTF-8?q?4.1=E4=BB=A5=E5=89=8D(=E5=90=AB=E3=82=80)?= =?UTF-8?q?=E3=81=AE=E5=AF=BE=E5=BF=9C=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=91=E3=82=A4=E3=83=AB=E5=88=86=E5=B2=90=E3=82=92=E5=BB=83?= =?UTF-8?q?=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Inspector/PMDInspector.cs | 6 ------ Editor/MMDLoader/PMDLoaderWindow.cs | 7 ------- Editor/MMDLoader/Private/AvatarSettingScript.cs | 6 +----- Editor/MMDLoader/Private/MMDConverter.cs | 6 ------ Editor/MMDLoader/Private/PMXConverter.cs | 6 ------ 5 files changed, 1 insertion(+), 30 deletions(-) diff --git a/Editor/Inspector/PMDInspector.cs b/Editor/Inspector/PMDInspector.cs index 84e5afb..2cd409a 100644 --- a/Editor/Inspector/PMDInspector.cs +++ b/Editor/Inspector/PMDInspector.cs @@ -64,13 +64,7 @@ public override void OnInspectorGUI() rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); // Mecanimを使うかどうか -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); -#else - GUI.enabled = false; - use_mecanim = EditorGUILayout.Toggle("Use Mecanim", false); - GUI.enabled = !EditorApplication.isPlaying; -#endif // IKを使うかどうか use_ik = EditorGUILayout.Toggle("Use IK", use_ik); diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index 5f68dd2..0ffab95 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -40,14 +40,7 @@ void OnGUI() { rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); // Mecanimを使うかどうか -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); -#else - bool old_gui_enabled = GUI.enabled; - GUI.enabled = false; - use_mecanim = EditorGUILayout.Toggle("Use Mecanim", false); - GUI.enabled = old_gui_enabled; -#endif // IKを使うかどうか use_ik = EditorGUILayout.Toggle("Use IK", use_ik); diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index 3726b9e..af47955 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -1,6 +1,4 @@ -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 - -using UnityEngine; +using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.Linq; @@ -315,5 +313,3 @@ void DisableIk() Avatar avatar_ = null; Animator animator_ = null; } - -#endif diff --git a/Editor/MMDLoader/Private/MMDConverter.cs b/Editor/MMDLoader/Private/MMDConverter.cs index 9ffca15..004ba9e 100644 --- a/Editor/MMDLoader/Private/MMDConverter.cs +++ b/Editor/MMDLoader/Private/MMDConverter.cs @@ -89,7 +89,6 @@ private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, b } // Mecanim設定 -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 if (use_mecanim_) { AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); avatar_setting.SettingAvatar(); @@ -101,9 +100,6 @@ private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, b } else { root_game_object_.AddComponent(); // アニメーション追加 } -#else - root_game_object_.AddComponent(); // アニメーション追加 -#endif return root_game_object_; } @@ -200,9 +196,7 @@ bool IsTransparentMaterial(PMD.PMDFormat.Material model_material, Texture2D text bool result = false; result = result || (model_material.alpha < 0.98f); //0.98f以上は不透明と見做す(0.98fに影生成情報を埋め込んでいる為) if (null != texture) { -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 result = result || texture.alphaIsTransparency; -#endif } return result; } diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 936ba6b..166869e 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -79,7 +79,6 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool } // Mecanim設定 -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 if (use_mecanim_) { //アニメーター追加 AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); @@ -92,9 +91,6 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool } else { root_game_object_.AddComponent(); // アニメーション追加 } -#else - root_game_object_.AddComponent(); // アニメーション追加 -#endif return root_game_object_; } @@ -487,9 +483,7 @@ bool IsTransparentMaterial(PMXFormat.Material material, Texture2D texture) { bool result = false; result = result || (material.diffuse_color.a < 1.0f); if (null != texture) { -#if !(UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1) //4.2以降 result = result || texture.alphaIsTransparency; -#endif } return result; } From e62444c45b8b2a56bb0949eb4d4b1965928b0525 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 16 Nov 2013 10:20:28 +0900 Subject: [PATCH 18/37] =?UTF-8?q?4.3=E3=81=A7=E3=81=AEobsolete=E8=AD=A6?= =?UTF-8?q?=E5=91=8A=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/ExpressionManagerEditor.cs | 4 ++++ Editor/MMDEngineEditor.cs | 16 ++++++++++++++++ Editor/MMDLoader/Private/MMDConverter.cs | 20 +++++++++++++++++++- Editor/MorphManagerEditor.cs | 4 ++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Editor/ExpressionManagerEditor.cs b/Editor/ExpressionManagerEditor.cs index 86fbf5d..a3ee361 100644 --- a/Editor/ExpressionManagerEditor.cs +++ b/Editor/ExpressionManagerEditor.cs @@ -71,7 +71,11 @@ public override void OnInspectorGUI() if (child.localPosition.z != value) { //変更が掛かったなら //Undo登録 +#if !UNITY_4_2 //4.3以降 + Undo.RecordObject(child, "Expression Change"); +#else Undo.RegisterUndo(child, "Expression Change"); +#endif //Z位置更新 Vector3 position = child.localPosition; position.z = value; diff --git a/Editor/MMDEngineEditor.cs b/Editor/MMDEngineEditor.cs index 39583d9..71df190 100644 --- a/Editor/MMDEngineEditor.cs +++ b/Editor/MMDEngineEditor.cs @@ -59,7 +59,11 @@ private bool OnInspectorGUIforOutlineWidth() if (self.outline_width != outline_width) { //変更が掛かったなら //Undo登録 +#if !UNITY_4_2 //4.3以降 + Undo.RecordObject(self, "Outline Width Change"); +#else Undo.RegisterUndo(self, "Outline Width Change"); +#endif //更新 self.outline_width = outline_width; @@ -82,7 +86,11 @@ private bool OnInspectorGUIforUseRigidbody() if (self.useRigidbody != use_rigidbody) { //変更が掛かったなら //Undo登録 +#if !UNITY_4_2 //4.3以降 + Undo.RecordObject(self, "Use Rigidbody Change"); +#else Undo.RegisterUndo(self, "Use Rigidbody Change"); +#endif //更新 self.useRigidbody = use_rigidbody; @@ -115,7 +123,11 @@ private bool OnInspectorGUIforIkList() if (ik.enabled != enabled) { //変更が掛かったなら //Undo登録 +#if !UNITY_4_2 //4.3以降 + Undo.RecordObject(ik, "Enabled Change"); +#else Undo.RegisterUndo(ik, "Enabled Change"); +#endif //更新 ik.enabled = enabled; //改変したIKのInspector更新 @@ -231,7 +243,11 @@ private bool OnInspectorGUIforShaderList() if (is_change_shader) { //変更が掛かったなら //Undo登録 +#if !UNITY_4_2 //4.3以降 + Undo.RecordObject(material, "Shader Change"); +#else Undo.RegisterUndo(material, "Shader Change"); +#endif SetShader(material, flag); is_update = true; diff --git a/Editor/MMDLoader/Private/MMDConverter.cs b/Editor/MMDLoader/Private/MMDConverter.cs index 004ba9e..baed843 100644 --- a/Editor/MMDLoader/Private/MMDConverter.cs +++ b/Editor/MMDLoader/Private/MMDConverter.cs @@ -1318,9 +1318,16 @@ void CreateKeysForRotation(MMD.VMD.VMDFormat format, AnimationClip clip, string AnimationCurve curve_y = new AnimationCurve(ry_keys); AnimationCurve curve_z = new AnimationCurve(rz_keys); // ここで回転オイラー角をセット(補間はクォータニオン) +#if !UNITY_4_2 //4.3以降 + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.x"),curve_x); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.y"),curve_y); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.z"),curve_z); +#else AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.x",curve_x); AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.y",curve_y); AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.z",curve_z); +#endif + } catch (KeyNotFoundException) { @@ -1397,9 +1404,15 @@ void CreateKeysForLocation(MMD.VMD.VMDFormat format, AnimationClip clip, string AnimationCurve curve_x = new AnimationCurve(ToKeyframesForLocation(lx_keys)); AnimationCurve curve_y = new AnimationCurve(ToKeyframesForLocation(ly_keys)); AnimationCurve curve_z = new AnimationCurve(ToKeyframesForLocation(lz_keys)); - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.x",curve_x); +#if !UNITY_4_2 //4.3以降 + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.x"),curve_x); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.y"),curve_y); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.z"),curve_z); +#else + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.x",curve_x); AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.y",curve_y); AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.z",curve_z); +#endif } } catch (KeyNotFoundException) @@ -1437,7 +1450,12 @@ void CreateKeysForSkin(MMD.VMD.VMDFormat format, AnimationClip clip) // Z軸移動にキーフレームを打つ AnimationCurve curve = new AnimationCurve(keyframe); +#if !UNITY_4_2 //4.3以降 + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve("Expression/" + skin.Key,typeof(Transform),"m_LocalPosition.z"),curve); +#else AnimationUtility.SetEditorCurve(clip,"Expression/" + skin.Key,typeof(Transform),"m_LocalPosition.z",curve); +#endif + } } diff --git a/Editor/MorphManagerEditor.cs b/Editor/MorphManagerEditor.cs index 15ad490..e8df936 100644 --- a/Editor/MorphManagerEditor.cs +++ b/Editor/MorphManagerEditor.cs @@ -95,7 +95,11 @@ private bool OnInspectorGUIforPanelList() if (child.localPosition.z != value) { //変更が掛かったなら //Undo登録 +#if !UNITY_4_2 //4.3以降 + Undo.RecordObject(child, "Morph Change"); +#else Undo.RegisterUndo(child, "Morph Change"); +#endif //Z位置更新 Vector3 position = child.localPosition; position.z = value; From 2e4e5a0723a5df6ad2b2db9111f33b7cc75bc8e2 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 12 Nov 2013 03:30:32 +0900 Subject: [PATCH 19/37] =?UTF-8?q?PMX2PMD:=E9=96=A2=E9=80=A3=E3=83=9C?= =?UTF-8?q?=E3=83=BC=E3=83=B3=E3=81=AE=E7=84=A1=E3=81=84=E5=89=9B=E4=BD=93?= =?UTF-8?q?=E3=81=8C=E6=9C=89=E3=82=8B=E3=81=A8=E3=82=AF=E3=83=A9=E3=83=83?= =?UTF-8?q?=E3=82=B7=E3=83=A5=E3=81=99=E3=82=8B=E4=B8=8D=E5=85=B7=E5=90=88?= =?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/PMXLoaderScript.PMX2PMD.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Editor/MMDLoader/Private/PMXLoaderScript.PMX2PMD.cs b/Editor/MMDLoader/Private/PMXLoaderScript.PMX2PMD.cs index 4720148..eadba11 100644 --- a/Editor/MMDLoader/Private/PMXLoaderScript.PMX2PMD.cs +++ b/Editor/MMDLoader/Private/PMXLoaderScript.PMX2PMD.cs @@ -10,7 +10,7 @@ public partial class PMXLoaderScript { /// /// PMDファイルのヘッダー取得 /// - /// PMDファイルのパス + /// PMXヘッダー /// ヘッダー public static PMDFormat.Header PMX2PMD(PMXFormat.Header pmx_header) { PMDFormat.Header pmd_header = ConvertHeader(pmx_header); @@ -20,7 +20,7 @@ public static PMDFormat.Header PMX2PMD(PMXFormat.Header pmx_header) { /// /// PMDファイルの取得 /// - /// PMDファイルのパス + /// PMXファイル /// 内部形式データ public static PMDFormat PMX2PMD(PMXFormat pmx) { PMDFormat result = new PMDFormat(); @@ -408,7 +408,12 @@ private static PMDFormat.Rigidbody ConvertRigidbody(PMXFormat pmx, int rigidbody result.shape_w = pmx_rigidbody.shape_size.x; result.shape_h = pmx_rigidbody.shape_size.y; result.shape_d = pmx_rigidbody.shape_size.z; - result.pos_pos = pmx_rigidbody.collider_position - pmx.bone_list.bone[pmx_rigidbody.rel_bone_index].bone_position; + result.pos_pos = pmx_rigidbody.collider_position; + if (pmx_rigidbody.rel_bone_index < pmx.bone_list.bone.Length) { + result.pos_pos -= pmx.bone_list.bone[pmx_rigidbody.rel_bone_index].bone_position; + } else { + result.pos_pos -= pmx.bone_list.bone[0].bone_position; + } result.pos_rot = pmx_rigidbody.collider_rotation; result.rigidbody_weight = pmx_rigidbody.weight; result.rigidbody_pos_dim = pmx_rigidbody.position_dim; From b7d811fa59d0bd95a7a76edb77db2639ca352df8 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 12 Nov 2013 03:30:59 +0900 Subject: [PATCH 20/37] =?UTF-8?q?PMD2PMX:=E5=88=9D=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/ModelAgent.cs | 76 ++-- .../Private/PMXLoaderScript.PMD2PMX.cs | 411 ++++++++++++++++++ Editor/MMDLoader/Private/PMXLoaderScript.cs | 20 +- 3 files changed, 452 insertions(+), 55 deletions(-) create mode 100644 Editor/MMDLoader/Private/PMXLoaderScript.PMD2PMX.cs diff --git a/Editor/MMDLoader/Private/ModelAgent.cs b/Editor/MMDLoader/Private/ModelAgent.cs index 5b58a64..4f4edaf 100644 --- a/Editor/MMDLoader/Private/ModelAgent.cs +++ b/Editor/MMDLoader/Private/ModelAgent.cs @@ -1,7 +1,6 @@ using UnityEngine; using UnityEditor; using System.Collections.Generic; -using MMD.PMD; namespace MMD { @@ -19,13 +18,13 @@ public ModelAgent(string file_path) { header_ = null; try { //PMX読み込みを試みる - header_ = PMXLoaderScript.GetPmdHeader(file_path_); + header_ = PMXLoaderScript.GetHeader(file_path_); } catch (System.FormatException) { //PMXとして読み込めなかったら //PMDとして読み込む - header_ = PMDLoaderScript.GetHeader(file_path_); + PMD.PMDFormat.Header pmd_header = PMDLoaderScript.GetHeader(file_path_); + header_ = PMXLoaderScript.PMD2PMX(pmd_header); } - format_ = null; } /// @@ -39,46 +38,52 @@ public ModelAgent(string file_path) { /// PMX Baseでインポートするか public void CreatePrefab(PMD.PMDConverter.ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale, bool is_pmx_base_import) { GameObject game_object; - Object prefab; + string prefab_path; if (is_pmx_base_import) { //PMX Baseでインポートする //PMXファイルのインポート - PMX.PMXFormat format = PMXLoaderScript.Import(file_path_); + PMX.PMXFormat pmx_format = null; + try { + //PMX読み込みを試みる + pmx_format = PMXLoaderScript.Import(file_path_); + } catch (System.FormatException) { + //PMXとして読み込めなかったら + //PMDとして読み込む + PMD.PMDFormat pmd_format = PMDLoaderScript.Import(file_path_); + pmx_format = PMXLoaderScript.PMD2PMX(pmd_format); + } + header_ = pmx_format.header; //ゲームオブジェクトの作成 - game_object = PMXConverter.CreateGameObject(format, use_rigidbody, use_mecanim, use_ik, scale); + game_object = PMXConverter.CreateGameObject(pmx_format, use_rigidbody, use_mecanim, use_ik, scale); - // プレファブに登録 - prefab = PrefabUtility.CreateEmptyPrefab(format.meta_header.folder + "/" + format.meta_header.name + ".prefab"); + // プレファブパスの設定 + prefab_path = pmx_format.meta_header.folder + "/" + pmx_format.meta_header.name + ".prefab"; } else { - //V2エクスポーターを使用しない + //PMXエクスポーターを使用しない //PMDファイルのインポート - if (null == format_) { - //まだ読み込んでいないなら読むこむ - try { - //PMX読み込みを試みる - format_ = PMXLoaderScript.PmdImport(file_path_); - } catch (System.FormatException) { - //PMXとして読み込めなかったら - //PMDとして読み込む - format_ = PMDLoaderScript.Import(file_path_); - } - header_ = format_.head; + PMD.PMDFormat pmd_format = null; + try { + //PMX読み込みを試みる + PMX.PMXFormat pmx_format = PMXLoaderScript.Import(file_path_); + pmd_format = PMXLoaderScript.PMX2PMD(pmx_format); + } catch (System.FormatException) { + //PMXとして読み込めなかったら + //PMDとして読み込む + pmd_format = PMDLoaderScript.Import(file_path_); } + header_ = PMXLoaderScript.PMD2PMX(pmd_format.head); //ゲームオブジェクトの作成 - game_object = PMDConverter.CreateGameObject(format_, shader_type, use_rigidbody, use_mecanim, use_ik, scale); + game_object = PMD.PMDConverter.CreateGameObject(pmd_format, shader_type, use_rigidbody, use_mecanim, use_ik, scale); - // プレファブに登録 - prefab = PrefabUtility.CreateEmptyPrefab(format_.folder + "/" + format_.name + ".prefab"); + // プレファブパスの設定 + prefab_path = pmd_format.folder + "/" + pmd_format.name + ".prefab"; } - PrefabUtility.ReplacePrefab(game_object, prefab); + // プレファブ化 + PrefabUtility.CreatePrefab(prefab_path, game_object, ReplacePrefabOptions.ConnectToPrefab); // アセットリストの更新 AssetDatabase.Refresh(); - - // 一度,表示されているモデルを削除して新しくPrefabのインスタンスを作る - GameObject.DestroyImmediate(game_object); - PrefabUtility.InstantiatePrefab(prefab); } /// @@ -99,8 +104,8 @@ public string name {get{ /// 英語表記モデル名 public string english_name {get{ string result = null; - if (null != format_) { - result = format_.eg_head.model_name_eg; + if (null != header_) { + result = header_.model_english_name; } return result; }} @@ -123,14 +128,13 @@ public string comment {get{ /// モデル製作者からの英語コメント public string english_comment {get{ string result = null; - if (null != format_) { - result = format_.eg_head.comment_eg; + if (null != header_) { + result = header_.english_comment; } return result; }} - string file_path_; - PMDFormat.Header header_; - PMDFormat format_; + string file_path_; + PMX.PMXFormat.Header header_; } } \ No newline at end of file diff --git a/Editor/MMDLoader/Private/PMXLoaderScript.PMD2PMX.cs b/Editor/MMDLoader/Private/PMXLoaderScript.PMD2PMX.cs new file mode 100644 index 0000000..1649222 --- /dev/null +++ b/Editor/MMDLoader/Private/PMXLoaderScript.PMD2PMX.cs @@ -0,0 +1,411 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using MMD.PMX; +using MMD.PMD; + +public partial class PMXLoaderScript { + + /// + /// PMXファイルのヘッダー取得 + /// + /// PMDヘッダー + /// ヘッダー + public static PMXFormat.Header PMD2PMX(PMDFormat.Header pmd_header) { + PMXFormat.Header pmx_header = ConvertHeader(pmd_header, null, null); + return pmx_header; + } + + /// + /// PMXファイルの取得 + /// + /// PMDファイル + /// 内部形式データ + public static PMXFormat PMD2PMX(PMDFormat pmd) { + PMXFormat result = new PMXFormat(); + result.meta_header = CreateMetaHeader(pmd); + result.header = ConvertHeader(pmd.head, pmd.eg_head, pmd); + result.vertex_list = ConvertVertexList(pmd); + result.face_vertex_list = ConvertFaceVertexList(pmd); + result.texture_list = ConvertTextureList(pmd); + result.material_list = ConvertMaterialList(pmd, x=>CreateTextureIndex(ref result.texture_list.texture_file, x)); + result.bone_list = ConvertBoneList(pmd); + result.morph_list = ConvertMorphList(pmd); + result.display_frame_list = ConvertDisplayFrameList(pmd); + result.rigidbody_list = ConvertRigidbodyList(pmd); + result.rigidbody_joint_list = ConvertRigidbodyJointList(pmd); + return result; + } + + /// + /// テクスチャインデックス取得用関数 + /// + /// テクスチャインデックス + /// テクスチャリスト + /// 検索するテクスチャ名 + private static uint CreateTextureIndex(ref string[] list, string name) { + uint result = uint.MaxValue; + for (int i = 0, i_max = list.Length; i < i_max; ++i) { + if (name == list[i]) { + //発見したらインデックスを返す + result = (uint)i; + break; + } + } + if (uint.MaxValue == result) { + //未発見なら + //末尾に登録して返す + string[] new_list = new string[list.Length + 1]; + System.Array.Copy(list, new_list, list.Length); + new_list[list.Length] = name; //最後に追加 + result = (uint)list.Length; + list = new_list; + } + return result; + } + + private static PMXFormat.MetaHeader CreateMetaHeader(PMDFormat pmd) { + PMXFormat.MetaHeader result = new PMXFormat.MetaHeader(); + result.path = pmd.path; + result.name = pmd.name; + result.folder = pmd.folder; + return result; + } + + private static PMXFormat.Header ConvertHeader(PMDFormat.Header pmd_header, PMDFormat.EnglishHeader pmd_english_header, PMDFormat pmd) { + PMXFormat.Header result = new PMXFormat.Header(); + result.magic = pmd_header.magic; + result.version = pmd_header.version; + + result.dataSize = 0; + result.encodeMethod = PMXFormat.Header.StringCode.Utf16le; + result.additionalUV = 0; + result.vertexIndexSize = PMXFormat.Header.IndexSize.Byte1; + result.textureIndexSize = PMXFormat.Header.IndexSize.Byte1; + result.materialIndexSize = PMXFormat.Header.IndexSize.Byte1; + result.boneIndexSize = PMXFormat.Header.IndexSize.Byte1; + result.morphIndexSize = PMXFormat.Header.IndexSize.Byte1; + result.rigidbodyIndexSize = PMXFormat.Header.IndexSize.Byte1; + if (null != pmd) { + result.vertexIndexSize = GetIndexSize(pmd.vertex_list.vertex.Length); + result.textureIndexSize = GetIndexSize(pmd.toon_texture_list.toon_texture_file.Length); + result.materialIndexSize = GetIndexSize(pmd.material_list.material.Length); + result.boneIndexSize = GetIndexSize(pmd.bone_list.bone.Length); + result.morphIndexSize = GetIndexSize(pmd.skin_list.skin_data.Length); + result.rigidbodyIndexSize = GetIndexSize(pmd.rigidbody_list.rigidbody.Length); + } + + result.model_name = pmd_header.model_name; + result.comment = pmd_header.comment; + result.model_english_name = ""; + result.english_comment = ""; + if (null != pmd_english_header) { + result.model_english_name = pmd_english_header.model_name_eg; + result.english_comment = pmd_english_header.comment_eg; + } else if (null != pmd) { + result.model_english_name = pmd.eg_head.model_name_eg; + result.english_comment = pmd.eg_head.comment_eg; + } + return result; + } + + private static PMXFormat.Header.IndexSize GetIndexSize(int size) { + PMXFormat.Header.IndexSize result; + if ((int)ushort.MaxValue <= size) { + result = PMXFormat.Header.IndexSize.Byte4; + } else if ((int)byte.MaxValue <= size) { + result = PMXFormat.Header.IndexSize.Byte2; + } else { + result = PMXFormat.Header.IndexSize.Byte1; + } + return result; + } + + private static PMXFormat.VertexList ConvertVertexList(PMDFormat pmd) { + PMXFormat.VertexList result = new PMXFormat.VertexList(); + result.vertex = pmd.vertex_list.vertex.Select(x=>ConvertVertex(x)).ToArray(); + return result; + } + + private static PMXFormat.Vertex ConvertVertex(PMDFormat.Vertex pmd_vertex) { + PMXFormat.Vertex result = new PMXFormat.Vertex(); + result.pos = pmd_vertex.pos; + result.normal_vec = pmd_vertex.normal_vec; + result.uv = pmd_vertex.uv; + result.add_uv = new Vector4[0]; + if (100 == pmd_vertex.bone_weight) { + //1頂点 + PMXFormat.BDEF1 bone_weight = new PMXFormat.BDEF1(); + bone_weight.bone1_ref = pmd_vertex.bone_num[0]; + result.bone_weight = bone_weight; + } else { + //2頂点 + PMXFormat.BDEF2 bone_weight = new PMXFormat.BDEF2(); + bone_weight.bone1_ref = pmd_vertex.bone_num[0]; + bone_weight.bone2_ref = pmd_vertex.bone_num[1]; + bone_weight.bone1_weight = pmd_vertex.bone_weight / 100.0f; + result.bone_weight = bone_weight; + } + result.edge_magnification = (float)pmd_vertex.edge_flag; + return result; + } + + private static PMXFormat.FaceVertexList ConvertFaceVertexList(PMDFormat pmd) { + PMXFormat.FaceVertexList result = new PMXFormat.FaceVertexList(); + result.face_vert_index = pmd.face_vertex_list.face_vert_index.Select(x=>(uint)x).ToArray(); + return result; + } + + private static PMXFormat.TextureList ConvertTextureList(PMDFormat pmd) { + PMXFormat.TextureList result = new PMXFormat.TextureList(); + result.texture_file = pmd.toon_texture_list.toon_texture_file.ToArray(); //複製する + return result; + } + + private static PMXFormat.MaterialList ConvertMaterialList(PMDFormat pmd, System.Func get_texture_index) { + PMXFormat.MaterialList result = new PMXFormat.MaterialList(); + result.material = new PMXFormat.Material[pmd.material_list.material.Length]; + for (int i = 0; i < result.material.Length; i++) { + result.material[i] = ConvertMaterial(pmd, i, get_texture_index); + } + return result; + } + + private static PMXFormat.Material ConvertMaterial(PMDFormat pmd, int material_index, System.Func get_texture_index) { + PMXFormat.Material result = new PMXFormat.Material(); + PMDFormat.Material pmd_material = pmd.material_list.material[material_index]; + + result.name = "材質_" + material_index.ToString(); + result.english_name = "Material_" + material_index.ToString(); + result.diffuse_color = new Color(pmd_material.diffuse_color.r, pmd_material.diffuse_color.g, pmd_material.diffuse_color.b, pmd_material.alpha); + result.specularity = pmd_material.specularity; + result.specular_color = pmd_material.specular_color; + result.ambient_color = pmd_material.mirror_color; + result.flag = new PMXFormat.Material.Flag(); + if (pmd_material.alpha < 1.0f) { + result.flag |= PMXFormat.Material.Flag.Reversible; + } + if (0 != pmd_material.edge_flag) { + result.flag |= PMXFormat.Material.Flag.Edge | PMXFormat.Material.Flag.CastShadow | PMXFormat.Material.Flag.CastSelfShadow; + } + if (!(0.98f == pmd_material.alpha)) { //浮動小数点の比較だけど、0.98fとの同値確認でPMXエディタの0.98と一致したので一旦これで。 + result.flag |= PMXFormat.Material.Flag.ReceiveSelfShadow; + } + result.edge_color = Color.black; + result.edge_size = 1.0f; + result.usually_texture_index = uint.MaxValue; + if (!string.IsNullOrEmpty(pmd_material.texture_file_name)) { + result.usually_texture_index = get_texture_index(pmd_material.texture_file_name); + } + result.sphere_texture_index = uint.MaxValue; + result.sphere_mode = PMXFormat.Material.SphereMode.Null; + if (!string.IsNullOrEmpty(pmd_material.sphere_map_name)) { + result.sphere_texture_index = get_texture_index(pmd_material.sphere_map_name); + switch (System.IO.Path.GetExtension(pmd_material.sphere_map_name)) { + case ".sph": result.sphere_mode = PMXFormat.Material.SphereMode.MulSphere; break; + case ".spa": result.sphere_mode = PMXFormat.Material.SphereMode.AddSphere; break; + default: break; + } + } + result.common_toon = pmd_material.toon_index; + result.toon_texture_index = ((0 < pmd_material.toon_index)? pmd_material.toon_index: uint.MaxValue); + result.memo = ""; + result.face_vert_count = pmd_material.face_vert_count; + return result; + } + + private static PMXFormat.BoneList ConvertBoneList(PMDFormat pmd) { + PMXFormat.BoneList result = new PMXFormat.BoneList(); + result.bone = new PMXFormat.Bone[pmd.bone_list.bone.Length]; + for (int i = 0, i_max = pmd.bone_list.bone.Length; i < i_max; ++i) { + result.bone[i] = ConvertBone(pmd, i); + } + return result; + } + + private static PMXFormat.Bone ConvertBone(PMDFormat pmd, int bone_index) { + PMXFormat.Bone result = new PMXFormat.Bone(); + PMDFormat.Bone pmd_bone = pmd.bone_list.bone[bone_index]; + + result.bone_name = pmd_bone.bone_name; + result.bone_english_name = ((null != pmd.eg_bone_name_list)? pmd.eg_bone_name_list.bone_name_eg[bone_index]: null); + result.bone_position = pmd_bone.bone_head_pos; + result.parent_bone_index = ((ushort.MaxValue == pmd_bone.parent_bone_index)? uint.MaxValue: (uint)pmd_bone.parent_bone_index); + result.transform_level = 0; + switch (pmd_bone.bone_type) { + case 0: //回転 + result.bone_flag = PMXFormat.Bone.Flag.Movable | PMXFormat.Bone.Flag.DisplayFlag | PMXFormat.Bone.Flag.CanOperate; + break; + case 1: //回転と移動 + result.bone_flag = PMXFormat.Bone.Flag.Movable | PMXFormat.Bone.Flag.Rotatable | PMXFormat.Bone.Flag.DisplayFlag | PMXFormat.Bone.Flag.CanOperate; + break; + case 2: //IK + result.bone_flag = PMXFormat.Bone.Flag.IkFlag | PMXFormat.Bone.Flag.DisplayFlag | PMXFormat.Bone.Flag.CanOperate; + break; + case 3: //不明 + goto default; + case 4: //IK影響下 + goto default; + case 5: //回転影響下 + goto default; //付与親に変換しないといけないのかも + case 6: //IK接続先 + goto default; + case 7: //非表示 + goto default; + case 8: //捻り + goto default; + case 9: //回転運動 + goto default; + default: + result.bone_flag = new PMXFormat.Bone.Flag(); + break; + } + result.position_offset = Vector3.zero; + result.connection_index = 0; + result.additional_parent_index = 0; + result.additional_rate = 0.0f; + result.axis_vector = Vector3.zero; + result.x_axis_vector = Vector3.zero; + result.z_axis_vector = Vector3.zero; + result.key_value = 0; + result.ik_data = ConvertIKData(pmd.ik_list.ik_data.Where(x=>x.ik_bone_index==bone_index).FirstOrDefault()); + return result; + } + + private static PMXFormat.IK_Data ConvertIKData(PMDFormat.IK pmd_ik) { + PMXFormat.IK_Data result = null; + if (null != pmd_ik) { + result = new PMXFormat.IK_Data(); + result.ik_bone_index = pmd_ik.ik_target_bone_index; + result.iterations = pmd_ik.iterations; + result.limit_angle = pmd_ik.control_weight * 4.0f; //PMXConverter側で4倍されるので逆補正 + result.ik_link = pmd_ik.ik_child_bone_index.Select(x=>ConvertIKLink(x)).ToArray(); + } + return result; + } + + private static PMXFormat.IK_Link ConvertIKLink(ushort ik_child_bone_index) { + PMXFormat.IK_Link result = new PMXFormat.IK_Link(); + result.target_bone_index = ik_child_bone_index; + return result; + } + + private static PMXFormat.MorphList ConvertMorphList(PMDFormat pmd) { + PMXFormat.MorphList result = new PMXFormat.MorphList(); + //頂点インデックス用辞書の作成 + PMDFormat.SkinData pmd_skin_data_base = pmd.skin_list.skin_data.Where(x=>0==x.skin_type).First(); + Dictionary morph_vertex_index_dictionary = new Dictionary(pmd_skin_data_base.skin_vert_data.Length); + for (uint i = 0, i_max = (uint)pmd_skin_data_base.skin_vert_data.Length; i < i_max; ++i) { + morph_vertex_index_dictionary.Add(i, pmd_skin_data_base.skin_vert_data[i].skin_vert_index); + } + //base以外の変換 + result.morph_data = new PMXFormat.MorphData[pmd.skin_list.skin_data.Where(x=>0!=x.skin_type).Count()]; //base分を除外 + int morph_data_count = 0; + for (int i = 0, i_max = pmd.skin_list.skin_data.Length; i < i_max; ++i) { + if (0 != pmd.skin_list.skin_data[i].skin_type) { + //base以外なら + string eg_skin_name = (((null != pmd.eg_skin_name_list) && (1 <= i))? pmd.eg_skin_name_list.skin_name_eg[i - 1]: null); + result.morph_data[morph_data_count++] = ConvertMorphData(pmd.skin_list.skin_data[i], eg_skin_name, morph_vertex_index_dictionary); + } + } + return result; + } + + private static PMXFormat.MorphData ConvertMorphData(PMDFormat.SkinData pmd_skin, string pmd_eg_skin_name, Dictionary morph_vertex_index_dictionary) { + PMXFormat.MorphData result = new PMXFormat.MorphData(); + result.morph_name = pmd_skin.skin_name; + result.morph_english_name = pmd_eg_skin_name; + result.handle_panel = (PMXFormat.MorphData.Panel)pmd_skin.skin_type; + result.morph_type = PMXFormat.MorphData.MorphType.Vertex; + result.morph_offset = pmd_skin.skin_vert_data.Select(x=>ConvertVertexMorphOffset(x, morph_vertex_index_dictionary)).ToArray(); + return result; + } + + private static PMXFormat.VertexMorphOffset ConvertVertexMorphOffset(PMDFormat.SkinVertexData pmd_skin_vertex_data, Dictionary morph_vertex_index_dictionary) { + PMXFormat.VertexMorphOffset result = new PMXFormat.VertexMorphOffset(); + result.vertex_index = morph_vertex_index_dictionary[pmd_skin_vertex_data.skin_vert_index]; + result.position_offset = pmd_skin_vertex_data.skin_vert_pos; + return result; + } + + private static PMXFormat.DisplayFrameList ConvertDisplayFrameList(PMDFormat pmd) { + PMXFormat.DisplayFrameList result = new PMXFormat.DisplayFrameList(); + result.display_frame = new PMXFormat.DisplayFrame[pmd.bone_display_list.bone_disp.Length]; + for (int i = 0, i_max = result.display_frame.Length; i < i_max; ++i) { + result.display_frame[i] = ConvertDisplayFrame(pmd, i); + } + return result; + } + + private static PMXFormat.DisplayFrame ConvertDisplayFrame(PMDFormat pmd, int bone_display_index) { + PMXFormat.DisplayFrame result = new PMXFormat.DisplayFrame(); + PMDFormat.BoneDisplay pmd_bone_display = pmd.bone_display_list.bone_disp[bone_display_index]; + result.display_name = pmd.bone_name_list.disp_name[pmd_bone_display.bone_disp_frame_index - 1]; + result.display_english_name = ((null != pmd.eg_bone_display_list)? pmd.eg_bone_display_list.disp_name_eg[pmd_bone_display.bone_disp_frame_index - 1]: null); + result.special_frame_flag = new byte(); + result.display_element = new []{new PMXFormat.DisplayElement()}; + result.display_element[0].element_target = pmd_bone_display.bone_disp_frame_index; + result.display_element[0].element_target_index = pmd_bone_display.bone_index; + return result; + } + + private static PMXFormat.RigidbodyList ConvertRigidbodyList(PMDFormat pmd) { + PMXFormat.RigidbodyList result = new PMXFormat.RigidbodyList(); + result.rigidbody = new PMXFormat.Rigidbody[pmd.rigidbody_list.rigidbody.Length]; + for (int i = 0, i_max = result.rigidbody.Length; i < i_max; ++i) { + result.rigidbody[i] = ConvertRigidbody(pmd, i); + } + return result; + } + + private static PMXFormat.Rigidbody ConvertRigidbody(PMDFormat pmd, int rigidbody_index) { + PMXFormat.Rigidbody result = new PMXFormat.Rigidbody(); + PMDFormat.Rigidbody pmd_rigidbody = pmd.rigidbody_list.rigidbody[rigidbody_index]; + result.name = pmd_rigidbody.rigidbody_name; + result.english_name = ""; + result.rel_bone_index = (uint)pmd_rigidbody.rigidbody_rel_bone_index; + result.group_index = pmd_rigidbody.rigidbody_group_index; + result.ignore_collision_group = pmd_rigidbody.rigidbody_group_target; + result.shape_type = (PMXFormat.Rigidbody.ShapeType)pmd_rigidbody.shape_type; + result.shape_size = new Vector3(pmd_rigidbody.shape_w, pmd_rigidbody.shape_h, pmd_rigidbody.shape_d); + result.collider_position = pmd_rigidbody.pos_pos; + if (pmd_rigidbody.rigidbody_rel_bone_index < pmd.bone_list.bone.Length) { + result.collider_position += pmd.bone_list.bone[pmd_rigidbody.rigidbody_rel_bone_index].bone_head_pos; + } else { + result.collider_position += pmd.bone_list.bone[0].bone_head_pos; + } + result.collider_rotation = pmd_rigidbody.pos_rot; + result.weight = pmd_rigidbody.rigidbody_weight; + result.position_dim = pmd_rigidbody.rigidbody_pos_dim; + result.rotation_dim = pmd_rigidbody.rigidbody_rot_dim; + result.recoil = pmd_rigidbody.rigidbody_recoil; + result.friction = pmd_rigidbody.rigidbody_friction; + result.operation_type = (PMXFormat.Rigidbody.OperationType)pmd_rigidbody.rigidbody_type; + return result; + } + + private static PMXFormat.RigidbodyJointList ConvertRigidbodyJointList(PMDFormat pmx) { + PMXFormat.RigidbodyJointList result = new PMXFormat.RigidbodyJointList(); + result.joint = pmx.rigidbody_joint_list.joint.Select(x=>ConvertJoint(x)).ToArray(); + return result; + } + + private static PMXFormat.Joint ConvertJoint(PMDFormat.Joint pmd_joint) { + PMXFormat.Joint result = new PMXFormat.Joint(); + result.name = pmd_joint.joint_name; + result.english_name = ""; + result.operation_type = PMXFormat.Joint.OperationType.Spring6DOF; + result.rigidbody_a = pmd_joint.joint_rigidbody_a; + result.rigidbody_b = pmd_joint.joint_rigidbody_b; + result.position = pmd_joint.joint_pos; + result.rotation = pmd_joint.joint_rot; + result.constrain_pos_lower = pmd_joint.constrain_pos_1; + result.constrain_pos_upper = pmd_joint.constrain_pos_2; + result.constrain_rot_lower = pmd_joint.constrain_rot_1; + result.constrain_rot_upper = pmd_joint.constrain_rot_2; + result.spring_position = pmd_joint.spring_pos; + result.spring_rotation = pmd_joint.spring_rot; + return result; + } +} diff --git a/Editor/MMDLoader/Private/PMXLoaderScript.cs b/Editor/MMDLoader/Private/PMXLoaderScript.cs index 9b9b306..77151e5 100644 --- a/Editor/MMDLoader/Private/PMXLoaderScript.cs +++ b/Editor/MMDLoader/Private/PMXLoaderScript.cs @@ -1,8 +1,8 @@ using UnityEngine; using UnityEditor; using System.Collections.Generic; -using System.IO; using System.Text; +using System.IO; using MMD.PMX; using MMD.PMD; @@ -28,24 +28,6 @@ public static PMXFormat Import(string file_path) { return loader.Import_(file_path); } - /// - /// PMXファイルのヘッダー取得 - /// - /// PMDファイルのパス - /// ヘッダー - public static PMDFormat.Header GetPmdHeader(string file_path) { - return PMX2PMD(GetHeader(file_path)); - } - - /// - /// PMXファイルのインポート - /// - /// PMDファイルのパス - /// 内部形式データ - public static PMDFormat PmdImport(string file_path) { - return PMX2PMD(Import(file_path)); - } - /// /// デフォルトコンストラクタ /// From 5434f171881f43181402246dac604f56f184479f Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 19 Nov 2013 23:20:09 +0900 Subject: [PATCH 21/37] =?UTF-8?q?=E6=9D=90=E8=B3=AA1=E3=81=A4=E3=81=A76553?= =?UTF-8?q?6=E9=A0=82=E7=82=B9=E3=82=92=E8=B6=85=E3=81=88=E3=82=8B?= =?UTF-8?q?=E3=83=A2=E3=83=87=E3=83=AB=E3=81=AE=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDEngineEditor.cs | 2 +- Editor/MMDLoader/Private/PMXConverter.cs | 141 ++++++++++++++++++----- 2 files changed, 111 insertions(+), 32 deletions(-) diff --git a/Editor/MMDEngineEditor.cs b/Editor/MMDEngineEditor.cs index 71df190..b7d2673 100644 --- a/Editor/MMDEngineEditor.cs +++ b/Editor/MMDEngineEditor.cs @@ -157,7 +157,7 @@ private bool OnInspectorGUIforShaderList() if (shader_display_) { //シェーダーリストを表示するなら SkinnedMeshRenderer[] renderers = self.GetComponentsInChildren(); - Material[] materials = renderers.SelectMany(x=>x.sharedMaterials).ToArray(); + Material[] materials = renderers.SelectMany(x=>x.sharedMaterials).Distinct().ToArray(); if (1 < renderers.Length) { //rendererが複数有る(≒PMX)なら //PMXでは名前の先頭にはマテリアルインデックスが有るのでそれを参考にソート diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 166869e..94d1624 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -100,14 +100,13 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool /// class MeshCreationInfo { public class Pack { - public uint material_index; //マテリアル - public uint plane_start; //面開始位置 - public uint plane_count; //面数 - public uint[] vertices; //頂点 + public uint material_index; //マテリアル + public uint[] plane_indices; //面 + public uint[] vertices; //頂点 } public Pack[] value; - public uint[] all_vertices; //総頂点 - public Dictionary reassign_dictionary; //頂点リアサインインデックス用辞書 + public uint[] all_vertices; //総頂点 + public Dictionary reassign_dictionary; //頂点リアサインインデックス用辞書 } /// @@ -168,13 +167,13 @@ MeshCreationInfo.Pack[] CreateMeshCreationInfoPacks() .Select(x=>{ MeshCreationInfo.Pack pack = new MeshCreationInfo.Pack(); pack.material_index = (uint)x; - pack.plane_count = format_.material_list.material[x].face_vert_count; - pack.plane_start = plane_start; - plane_start += pack.plane_count; - pack.vertices = format_.face_vertex_list.face_vert_index.Skip((int)pack.plane_start) - .Take((int)pack.plane_count) //面頂点インデックス取り出し - .Distinct() //重複削除 - .ToArray(); + uint plane_count = format_.material_list.material[x].face_vert_count; + pack.plane_indices = format_.face_vertex_list.face_vert_index.Skip((int)plane_start) + .Take((int)plane_count) + .ToArray(); + pack.vertices = pack.plane_indices.Distinct() //重複削除 + .ToArray(); + plane_start += plane_count; return pack; }) .ToArray(); @@ -188,6 +187,8 @@ MeshCreationInfo[] CreateMeshCreationInfoMulti() { //マテリアル単位のMeshCreationInfo.Packを作成する MeshCreationInfo.Pack[] packs = CreateMeshCreationInfoPacks(); + //マテリアル細分化 + packs = SplitSubMesh(packs); //頂点数の多い順に並べる(メッシュ分割アルゴリズム上、後半に行く程頂点数が少ない方が敷き詰め効率が良い) System.Array.Sort(packs, (x,y)=>y.vertices.Length - x.vertices.Length); @@ -224,7 +225,86 @@ MeshCreationInfo[] CreateMeshCreationInfoMulti() } while (packs.Any(x=>null!=x)); //使用していないマテリアルが為るならループ return result.ToArray(); } - + + /// + /// 1マテリアルの頂点数が1メッシュで表現出来ない場合に分割する + /// + /// メッシュ作成情報のマテリアルパック + /// メッシュ作成情報のマテリアルパック + MeshCreationInfo.Pack[] SplitSubMesh(MeshCreationInfo.Pack[] packs) + { + MeshCreationInfo.Pack[] result = packs; + if (packs.Any(x=>c_max_vertex_count_in_mesh<=x.vertices.Length)) { + //1メッシュに収まらないマテリアルが有るなら + List result_list = new List(); + foreach (var pack in packs) { + if (c_max_vertex_count_in_mesh <= pack.vertices.Length) { + //1メッシュに収まらないなら + //分離 + var split_pack = SplitSubMesh(pack); + foreach (var i in split_pack) { + result_list.Add(i); + } + } else { + //1メッシュに収まるなら + //素通し + result_list.Add(pack); + } + } + result = result_list.ToArray(); + } + return result; + } + + /// + /// 1マテリアルの頂点数が1メッシュで表現出来ないので分割する + /// + /// メッシュ作成情報のマテリアルパック + /// メッシュ作成情報のマテリアルパック + List SplitSubMesh(MeshCreationInfo.Pack pack) + { + List result = new List(); + //1メッシュに収まらないなら + uint plane_end = (uint)pack.plane_indices.Length; + uint plane_start = 0; + while (plane_start < plane_end) { + //まだ面が有るなら + uint plane_count = 0; + uint vertex_count = 0; + while (true) { + //現在の頂点数から考えると、余裕分の1/3迄の数の面は安定して入る + //はみ出て欲しいから更に1面(3頂点)を足す + plane_count += (c_max_vertex_count_in_mesh - vertex_count) / 3 * 3 + 3; + vertex_count = (uint)pack.plane_indices.Skip((int)plane_start) //面頂点インデックス取り出し(先頭) + .Take((int)plane_count) //面頂点インデックス取り出し(末尾) + .Distinct() //重複削除 + .Count(); //個数取得 + if (c_max_vertex_count_in_mesh <= vertex_count) { + //1メッシュを超えているなら + //此処でのメッシュ超えは必ずc_max_vertex_count_in_meshぎりぎりで有り、1面(3頂点)を1つ取れば収まる様になっている + plane_count -= 3; + break; + } + if (plane_end <= (plane_start + plane_count)) { + //面の最後なら + break; + } + } + //分離分を戻り値の追加 + MeshCreationInfo.Pack result_pack = new MeshCreationInfo.Pack();; + result_pack.material_index = pack.material_index; + result_pack.plane_indices = pack.plane_indices.Skip((int)plane_start) //面頂点インデックス取り出し(先頭) + .Take((int)plane_count) //面頂点インデックス取り出し(末尾) + .ToArray(); + result_pack.vertices = result_pack.plane_indices.Distinct() //重複削除 + .ToArray(); + result.Add(result_pack); + //開始点を後ろに + plane_start += plane_count; + } + return result; + } + /// /// メッシュ作成 /// @@ -312,10 +392,8 @@ void SetSubMesh(Mesh mesh, MeshCreationInfo creation_info) mesh.subMeshCount = creation_info.value.Length; for (int i = 0, i_max = creation_info.value.Length; i < i_max; ++i) { //format_.face_vertex_list.face_vert_indexを[start](含む)から[start+count](含まず)迄取り出し - int[] indices = format_.face_vertex_list.face_vert_index.Skip((int)creation_info.value[i].plane_start) - .Take((int)creation_info.value[i].plane_count) - .Select(x=>(int)creation_info.reassign_dictionary[x]) //頂点リアサインインデックス変換 - .ToArray(); + int[] indices = creation_info.value[i].plane_indices.Select(x=>(int)creation_info.reassign_dictionary[x]) //頂点リアサインインデックス変換 + .ToArray(); mesh.SetTriangles(indices, i); } } @@ -344,12 +422,16 @@ void CreateAssetForMesh(Mesh mesh, int index) /// メッシュ作成情報 Material[][] CreateMaterials(MeshCreationInfo[] creation_info) { + //全マテリアルを作成 + Material[] materials = EntryAttributesForMaterials(); + CreateAssetForMaterials(materials); + + //メッシュ単位へ振り分け Material[][] result = new Material[creation_info.Length][]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { - Material[] materials = EntryAttributesForMaterials(creation_info[i]); - CreateAssetForMaterials(materials, creation_info[i]); - result[i] = materials; + result[i] = creation_info[i].value.Select(x=>materials[x.material_index]).ToArray(); } + return result; } @@ -357,11 +439,10 @@ Material[][] CreateMaterials(MeshCreationInfo[] creation_info) /// マテリアルに基本情報(シェーダー・カラー・テクスチャ)を登録する /// /// マテリアル - /// メッシュ作成情報 - Material[] EntryAttributesForMaterials(MeshCreationInfo creation_info) + Material[] EntryAttributesForMaterials() { - return creation_info.value.Select(x=>ConvertMaterial(format_.material_list.material[x.material_index])) - .ToArray(); + return format_.material_list.material.Select(x=>ConvertMaterial(x)) + .ToArray(); } /// @@ -561,9 +642,8 @@ bool IsNoReceiveShadowMaterial(PMXFormat.Material material) { /// /// マテリアルをProjectに登録する /// - /// 対象マテリアル - /// メッシュ作成情報 - void CreateAssetForMaterials(Material[] materials, MeshCreationInfo creation_info) { + /// 対象マテリアル + void CreateAssetForMaterials(Material[] materials) { // 適当なフォルダに投げる string path = format_.meta_header.folder + "/Materials/"; if (!System.IO.Directory.Exists(path)) { @@ -571,9 +651,8 @@ void CreateAssetForMaterials(Material[] materials, MeshCreationInfo creation_inf } for (int i = 0, i_max = materials.Length; i < i_max; ++i) { - uint material_index = creation_info.value[i].material_index; - string name = GetFilePathString(format_.material_list.material[material_index].name); - string file_name = path + material_index.ToString() + "_" + name + ".asset"; + string name = GetFilePathString(format_.material_list.material[i].name); + string file_name = path + i.ToString() + "_" + name + ".asset"; AssetDatabase.CreateAsset(materials[i], file_name); } } From 187ebeb8ceacce00245320ac4cdf03f2f50b265a Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 26 Nov 2013 08:52:00 +0900 Subject: [PATCH 22/37] =?UTF-8?q?MMDEngineEditor:ShaderList=E3=81=AB?= =?UTF-8?q?=E6=9D=90=E8=B3=AA=E5=90=8D=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99?= =?UTF-8?q?=E3=82=8B=E6=A7=98=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDEngineEditor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Editor/MMDEngineEditor.cs b/Editor/MMDEngineEditor.cs index b7d2673..40b4f0d 100644 --- a/Editor/MMDEngineEditor.cs +++ b/Editor/MMDEngineEditor.cs @@ -207,12 +207,11 @@ private bool OnInspectorGUIforShaderList() , new {flag=ShaderFlag.Hidden, reverse=false} }; //マテリアル - int material_index = 0; foreach (var material in materials) { EditorGUILayout.BeginHorizontal(); { //ラベル - EditorGUILayout.LabelField(new GUIContent((material_index++).ToString(), material.name), GUILayout.Width(64)); + EditorGUILayout.LabelField(new GUIContent(material.name, material.name), GUILayout.Width(64)); //シェーダー if (IsMmdShader(material)) { //MMDシェーダーなら From 8f12896e2570b10fdd44f4baba1cd164dcd0d5fe Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 3 Dec 2013 03:30:10 +0900 Subject: [PATCH 23/37] =?UTF-8?q?=E7=94=BB=E8=A7=92=E3=82=84=E3=82=B9?= =?UTF-8?q?=E3=82=B1=E3=83=BC=E3=83=AB=E3=81=AB=E4=BE=9D=E3=81=A3=E3=81=A6?= =?UTF-8?q?=E3=82=A8=E3=83=83=E3=82=B8=E5=B9=85=E3=81=8C=E5=A4=89=E3=82=8F?= =?UTF-8?q?=E3=82=8B=E4=B8=8D=E5=85=B7=E5=90=88=E3=81=AE=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20=E3=82=A8=E3=83=83=E3=82=B8=E3=81=AB=E3=82=A8=E3=83=83?= =?UTF-8?q?=E3=82=B8=E4=B8=8D=E9=80=8F=E6=98=8E=E5=BA=A6=E3=81=8C=E5=8F=8D?= =?UTF-8?q?=E6=98=A0=E3=81=95=E3=82=8C=E3=81=A6=E3=81=84=E3=81=AA=E3=81=84?= =?UTF-8?q?=E4=B8=8D=E5=85=B7=E5=90=88=E3=81=AE=E4=BF=AE=E6=AD=A3=20?= =?UTF-8?q?=E3=82=A8=E3=83=87=E3=82=A3=E3=83=88=E6=99=82=E3=81=AB=E6=96=BC?= =?UTF-8?q?=E3=81=91=E3=82=8B=E3=82=A8=E3=83=83=E3=82=B8=E5=B9=85=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=83=AB=E3=82=BF=E3=82=A4=E3=83=A0=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E3=81=AE=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDEngineEditor.cs | 69 ++++++++++++++----- Editor/MMDLoader/Private/MMDConverter.cs | 15 ++-- Editor/MMDLoader/Private/PMXConverter.cs | 8 ++- Resources/MMDEngine.cs | 13 ++-- .../Shaders/MeshPmdMaterialVertFrag.cginc | 11 +-- 5 files changed, 79 insertions(+), 37 deletions(-) diff --git a/Editor/MMDEngineEditor.cs b/Editor/MMDEngineEditor.cs index 40b4f0d..dc1f1fa 100644 --- a/Editor/MMDEngineEditor.cs +++ b/Editor/MMDEngineEditor.cs @@ -53,22 +53,44 @@ private bool OnInspectorGUIforOutlineWidth() { MMDEngine self = (MMDEngine)target; bool is_update = false; + +#if !MFU_DISABLE_LEGACY_DATA_SUPPORT + if (0 == self.material_outline_widths.Length) { + //material_outline_widthsが設定されていないなら(昔の変換データ) + Material[] materials = GetMaterials(self); + if (0 < materials.Length) { + //マテリアルが有り、今のエッジ幅が0.0fで無いなら + //データ生成を試みる + self.material_outline_widths = materials.Select(x=>x.GetFloat("_OutlineWidth")).ToArray(); + } + } +#endif float outline_width = self.outline_width; outline_width = EditorGUILayout.Slider("Outline Width", outline_width, 0.0f, 2.0f); if (self.outline_width != outline_width) { //変更が掛かったなら + Material[] materials = GetMaterials(self); //Undo登録 + var record_objects = materials.Select(x=>(UnityEngine.Object)x) //マテリアル全てと + .Concat(new UnityEngine.Object[]{self}) //UnityEngine + .ToArray(); #if !UNITY_4_2 //4.3以降 - Undo.RecordObject(self, "Outline Width Change"); + Undo.RecordObjects(record_objects, "Outline Width Change"); #else - Undo.RegisterUndo(self, "Outline Width Change"); + Undo.RegisterUndo(record_objects, "Outline Width Change"); #endif //更新 + const float c_default_scale = 0.085f; //0.085fの時にMMDと一致する様にしているので、それ以外なら補正 self.outline_width = outline_width; + foreach (var i in Enumerable.Range(0, materials.Length) + .Select(x=>new {material = materials[x], edge_size = self.material_outline_widths[x]})) { + i.material.SetFloat("_OutlineWidth", i.edge_size * outline_width * self.scale / c_default_scale); + } is_update = true; } + return is_update; } @@ -141,7 +163,7 @@ private bool OnInspectorGUIforIkList() } return is_update; } - + /// /// シェーダーリストの為のInspector描画 /// @@ -156,21 +178,7 @@ private bool OnInspectorGUIforShaderList() //シェーダーリスト内部 if (shader_display_) { //シェーダーリストを表示するなら - SkinnedMeshRenderer[] renderers = self.GetComponentsInChildren(); - Material[] materials = renderers.SelectMany(x=>x.sharedMaterials).Distinct().ToArray(); - if (1 < renderers.Length) { - //rendererが複数有る(≒PMX)なら - //PMXでは名前の先頭にはマテリアルインデックスが有るのでそれを参考にソート - //PMDではrendererが1つしか無く、かつソート済みの為不要 - System.Array.Sort(materials, (x,y)=>{ - string x_name = x.name.Substring(0, x.name.IndexOf('_')); - string y_name = y.name.Substring(0, y.name.IndexOf('_')); - int x_int, y_int; - Int32.TryParse(x_name, out x_int); - Int32.TryParse(y_name, out y_int); - return x_int - y_int; - }); - } + Material[] materials = GetMaterials(self); GUIStyle style = new GUIStyle(); style.margin.left = 10; EditorGUILayout.BeginVertical(style); @@ -411,6 +419,31 @@ static Shader CreateShaderFromShaderFlag(ShaderFlag flag) { return result; } + /// + /// 本来の順序で材質一覧の取得 + /// + /// 材質一覧 + /// 材質を取得するMMDEngine + static Material[] GetMaterials(MMDEngine engine) + { + SkinnedMeshRenderer[] renderers = engine.GetComponentsInChildren(); + Material[] result = renderers.SelectMany(x=>x.sharedMaterials).Distinct().ToArray(); + if (1 < renderers.Length) { + //rendererが複数有る(≒PMX)なら + //PMXでは名前の先頭にはマテリアルインデックスが有るのでそれを参考にソート + //PMDではrendererが1つしか無く、かつソート済みの為不要 + System.Array.Sort(result, (x,y)=>{ + string x_name = x.name.Substring(0, x.name.IndexOf('_')); + string y_name = y.name.Substring(0, y.name.IndexOf('_')); + int x_int, y_int; + Int32.TryParse(x_name, out x_int); + Int32.TryParse(y_name, out y_int); + return x_int - y_int; + }); + } + return result; + } + [Flags] private enum ShaderFlag { MmdShader = 1<< 0, //MMDシェーダー diff --git a/Editor/MMDLoader/Private/MMDConverter.cs b/Editor/MMDLoader/Private/MMDConverter.cs index baed843..78cd7bd 100644 --- a/Editor/MMDLoader/Private/MMDConverter.cs +++ b/Editor/MMDLoader/Private/MMDConverter.cs @@ -62,7 +62,10 @@ private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, b BuildingBindpose(mesh, materials, bones); MMDEngine engine = root_game_object_.AddComponent(); + //スケール・エッジ幅 engine.scale = scale_; + engine.outline_width = default_outline_width; + engine.material_outline_widths = Enumerable.Repeat(1.0f, materials.Length).ToArray(); // IKの登録 if (use_ik_) @@ -326,10 +329,11 @@ void EntryColors(Material[] mats) mats[i].SetFloat("_Opacity", pmdMat.alpha); mats[i].SetColor("_SpecularColor", pmdMat.specular_color); mats[i].SetFloat("_Shininess", pmdMat.specularity); + // エッジ + const float c_default_scale = 0.085f; //0.085fの時にMMDと一致する様にしているので、それ以外なら補正 + mats[i].SetFloat("_OutlineWidth", default_outline_width * scale_ / c_default_scale); + mats[i].SetColor("_OutlineColor", default_outline_color); - // エッジ - mats[i].SetFloat("_OutlineWidth", 0.2f); // これぐらいがいい気がする - // ここでスフィアマップ string path = format_.folder + "/" + pmdMat.sphere_map_name; Texture sphere_map; @@ -1003,7 +1007,10 @@ private static string GetFilePathString(string src) { .Replace("\n", string.Empty) .Replace("\r", string.Empty); } - + + static float default_outline_width = 0.2f; //標準エッジ幅 + static Color default_outline_color = Color.black; //標準エッジ色 + GameObject root_game_object_; PMDFormat format_; ShaderType shader_type_; diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 94d1624..7801972 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -45,8 +45,11 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool scale_ = scale; root_game_object_ = new GameObject(format_.meta_header.name); MMDEngine engine = root_game_object_.AddComponent(); //MMDEngine追加 + //スケール・エッジ幅 engine.scale = scale_; - + engine.outline_width = 1.0f; + engine.material_outline_widths = format.material_list.material.Select(x=>x.edge_size).ToArray(); + MeshCreationInfo[] creation_info = CreateMeshCreationInfo(); // メッシュを作成する為の情報を作成 Mesh[] mesh = CreateMesh(creation_info); // メッシュの生成・設定 Material[][] materials = CreateMaterials(creation_info); // マテリアルの生成・設定 @@ -470,7 +473,8 @@ Material ConvertMaterial(PMXFormat.Material material) result.SetColor("_SpecularColor", material.specular_color); result.SetFloat("_Shininess", material.specularity); // エッジ - result.SetFloat("_OutlineWidth", material.edge_size); + const float c_default_scale = 0.085f; //0.085fの時にMMDと一致する様にしているので、それ以外なら補正 + result.SetFloat("_OutlineWidth", material.edge_size * scale_ / c_default_scale); result.SetColor("_OutlineColor", material.edge_color); // スフィアテクスチャ diff --git a/Resources/MMDEngine.cs b/Resources/MMDEngine.cs index 2a2cefc..7a4b231 100644 --- a/Resources/MMDEngine.cs +++ b/Resources/MMDEngine.cs @@ -6,12 +6,15 @@ public class MMDEngine : MonoBehaviour { public float scale = 1.0f; //読み込みスケール - public float outline_width = 0.1f; public bool useRigidbody = false; public int[] groupTarget; // 非衝突剛体リスト public GameObject[] rigids; // 剛体リスト public GameObject[] joints; // ConfigurableJointの入っているボーンのリスト - +#if UNITY_EDITOR + public float outline_width; //エッジ幅係数(エディタ用) + public float[] material_outline_widths; //材質のエッジ幅(エディタ用) +#endif + // 訳があってこうなってる public int[] ignore1; public int[] ignore2; @@ -39,12 +42,6 @@ public class MMDEngine : MonoBehaviour { // Use this for initialization void Start () { - SkinnedMeshRenderer[] renderers = GetComponentsInChildren(); - foreach (var m in renderers.SelectMany(x=>x.sharedMaterials)) - { - m.SetFloat("_OutlineWidth", this.outline_width); - } - if (useRigidbody) { ignoreList = new List(); diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialVertFrag.cginc b/Resources/PMDMaterial/Shaders/MeshPmdMaterialVertFrag.cginc index 915da8f..f811a78 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialVertFrag.cginc +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialVertFrag.cginc @@ -29,14 +29,15 @@ struct v2f v2f vert( appdata_base v ) { v2f o; - float4 pos = mul( UNITY_MATRIX_MVP, v.vertex ); - float width = 0.01 * _OutlineWidth; - float4 edge_pos = v.vertex + pos.w * width * float4( v.normal, 0.0 ); - o.pos = mul( UNITY_MATRIX_MVP, edge_pos ); + float4 pos = mul(UNITY_MATRIX_MVP, v.vertex); + float4 normal = mul(UNITY_MATRIX_MVP, float4(v.normal, 0.0)); + float width = _OutlineWidth / 1024.0; //目コピ調整値(算術根拠無し) + float depth_offset = pos.z / 4194304.0; //僅かに奥に移動(floatの仮数部は23bitなので(1<<21)程度で割った値は丸めに入らないが非常に小さな値の筈) + o.pos = pos + normal * float4(width, width, 0.0, 0.0) + float4(0.0, 0.0, depth_offset, 0.0); return o; } half4 frag( v2f i ) : COLOR { - return half4( _OutlineColor.rgb, _Opacity ); + return half4( _OutlineColor.rgb, _OutlineColor.a * _Opacity ); } From 524b59fee1ea2660919b836fd73d18ee0ebb4a7f Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Thu, 19 Dec 2013 02:03:14 +0900 Subject: [PATCH 24/37] =?UTF-8?q?=E9=80=8F=E9=81=8E=E3=83=94=E3=82=AF?= =?UTF-8?q?=E3=82=BB=E3=83=AB=E3=81=AF=E6=8F=8F=E7=94=BB=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=84=E6=A7=98=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...aterial-Trans-CullBack-NoCastShadow.shader | 1 + .../MeshPmdMaterial-Trans-CullBack.shader | 9 +++++ .../MeshPmdMaterial-Trans-NoCastShadow.shader | 2 + .../Shaders/MeshPmdMaterial-Trans.shader | 10 +++++ ...Outline-Trans-CullBack-NoCastShadow.shader | 1 + ...shPmdMaterialOutline-Trans-CullBack.shader | 9 +++++ ...dMaterialOutline-Trans-NoCastShadow.shader | 2 + .../MeshPmdMaterialOutline-Trans.shader | 10 +++++ .../MeshPmdMaterialShadowVertFrag.cginc | 40 +++++++++++++++++++ 9 files changed, 84 insertions(+) create mode 100644 Resources/PMDMaterial/Shaders/MeshPmdMaterialShadowVertFrag.cginc diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack-NoCastShadow.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack-NoCastShadow.shader index 0daf547..e1eaa49 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack-NoCastShadow.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack-NoCastShadow.shader @@ -43,6 +43,7 @@ Shader "MMD/Transparent/PMDMaterial-CullBack-NoCastShadow" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack.shader index 20e8d2c..afe7482 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-CullBack.shader @@ -43,6 +43,7 @@ Shader "MMD/Transparent/PMDMaterial-CullBack" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -58,6 +59,14 @@ Shader "MMD/Transparent/PMDMaterial-CullBack" Cull Off Lighting Off //Offset [_ShadowBias], [_ShadowBiasSlope] //使えない様なのでコメントアウト + AlphaTest Greater 0.25 + + CGPROGRAM + #pragma vertex shadow_vert + #pragma fragment shadow_frag + #include "UnityCG.cginc" + #include "MeshPmdMaterialShadowVertFrag.cginc" + ENDCG } } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-NoCastShadow.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-NoCastShadow.shader index fd9ab35..2690bf0 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-NoCastShadow.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans-NoCastShadow.shader @@ -43,6 +43,7 @@ Shader "MMD/Transparent/PMDMaterial-NoCastShadow" Cull Front ZWrite Off Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -52,6 +53,7 @@ Shader "MMD/Transparent/PMDMaterial-NoCastShadow" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans.shader index f33525a..8a09788 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterial-Trans.shader @@ -43,6 +43,7 @@ Shader "MMD/Transparent/PMDMaterial" Cull Front ZWrite Off Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -52,6 +53,7 @@ Shader "MMD/Transparent/PMDMaterial" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -67,6 +69,14 @@ Shader "MMD/Transparent/PMDMaterial" Cull Off Lighting Off //Offset [_ShadowBias], [_ShadowBiasSlope] //使えない様なのでコメントアウト + AlphaTest Greater 0.25 + + CGPROGRAM + #pragma vertex shadow_vert + #pragma fragment shadow_frag + #include "UnityCG.cginc" + #include "MeshPmdMaterialShadowVertFrag.cginc" + ENDCG } } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader index 373601c..d640519 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader @@ -46,6 +46,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-CullBack-NoCastShadow" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader index 0825003..372464b 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader @@ -46,6 +46,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-CullBack" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -74,6 +75,14 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-CullBack" Cull Off Lighting Off //Offset [_ShadowBias], [_ShadowBiasSlope] //使えない様なのでコメントアウト + AlphaTest Greater 0.25 + + CGPROGRAM + #pragma vertex shadow_vert + #pragma fragment shadow_frag + #include "UnityCG.cginc" + #include "MeshPmdMaterialShadowVertFrag.cginc" + ENDCG } } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader index f67d531..5c4f10a 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader @@ -45,6 +45,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-NoCastShadow" Cull Front ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -54,6 +55,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-NoCastShadow" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader index 8f4e4e5..d1a21b5 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader @@ -46,6 +46,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline" Cull Front ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -55,6 +56,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline" Cull Back ZWrite On Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater 0.0 CGPROGRAM #pragma surface surf MMD #include "MeshPmdMaterialSurface.cginc" @@ -83,6 +85,14 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline" Cull Off Lighting Off //Offset [_ShadowBias], [_ShadowBiasSlope] //使えない様なのでコメントアウト + AlphaTest Greater 0.25 + + CGPROGRAM + #pragma vertex shadow_vert + #pragma fragment shadow_frag + #include "UnityCG.cginc" + #include "MeshPmdMaterialShadowVertFrag.cginc" + ENDCG } } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialShadowVertFrag.cginc b/Resources/PMDMaterial/Shaders/MeshPmdMaterialShadowVertFrag.cginc new file mode 100644 index 0000000..a3552f8 --- /dev/null +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialShadowVertFrag.cginc @@ -0,0 +1,40 @@ +/* + * MMD Shader for Unity + * + * Copyright 2012 Masataka SUMI, Takahiro INOUE + * + *    Licensed under the Apache License, Version 2.0 (the "License"); + *    you may not use this file except in compliance with the License. + *    You may obtain a copy of the License at + * + *        http://www.apache.org/licenses/LICENSE-2.0 + * + *    Unless required by applicable law or agreed to in writing, software + *    distributed under the License is distributed on an "AS IS" BASIS, + *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + *    See the License for the specific language governing permissions and + *    limitations under the License. + */ +float _Opacity; +sampler2D _MainTex; +float4 _MainTex_ST; + +struct v2f +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; +}; + +v2f shadow_vert( appdata_img v ) +{ + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); + return o; +} + +half4 shadow_frag( v2f i ) : COLOR +{ + float4 tex_color = tex2D(_MainTex, i.uv); + return half4(0, 0, 0, tex_color.a * _Opacity); +} From 743087a1d38b511016490b6eecc770bb3f6549f4 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Wed, 18 Sep 2013 00:57:53 +0900 Subject: [PATCH 25/37] =?UTF-8?q?PMXConverter:=E3=83=9E=E3=83=86=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=83=AB=E3=81=AE=E9=80=8F=E9=81=8E=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=81=AB=E3=83=86=E3=82=AF=E3=82=B9=E3=83=81=E3=83=A3=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=83=E3=83=88=E3=82=92=E5=8F=82?= =?UTF-8?q?=E7=85=A7=E3=81=99=E3=82=8B=E6=A7=98=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/PMXConverter.cs | 30 ++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 7801972..93e3f1a 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -566,9 +566,35 @@ string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture) { /// シェーダーに設定するメインテクスチャ bool IsTransparentMaterial(PMXFormat.Material material, Texture2D texture) { bool result = false; - result = result || (material.diffuse_color.a < 1.0f); + result = result || (material.diffuse_color.a < 1.0f); //アルファ値が透過かの確認 if (null != texture) { - result = result || texture.alphaIsTransparency; + result = result || texture.alphaIsTransparency; //alphaIsTransparencyフラグが透過かの確認 + if (!result) { + //テクスチャフォーマットから透過かの確認 + switch (texture.format) { + case TextureFormat.RGB24: break; //各色が8 ビットのテクスチャフォーマット + case TextureFormat.RGB565: break; //赤(5ビット)、緑(6ビット)、青(5ビット)のテクスチャフォーマット + case TextureFormat.DXT1: break; //圧縮されたテクスチャフォーマット + case TextureFormat.PVRTC_RGB2: break; //1ピクセル2ビットの圧縮されたテクスチャフォーマット(iOS 専用) + case TextureFormat.PVRTC_RGB4: break; //1ピクセル4ビットの圧縮されたテクスチャフォーマット(iOS 専用) + case TextureFormat.ETC_RGB4: break; //1ピクセル4ビットの圧縮されたテクスチャフォーマット(OpenGL ES 2.0 専用) + case TextureFormat.ATC_RGB4: break; //1ピクセル4ビットの圧縮されたテクスチャフォーマット(ATITC専用) + case TextureFormat.ATC_RGBA8: break; //1ピクセル8ビットの圧縮されたテクスチャフォーマット(ATITC専用) + case TextureFormat.BGRA32: break; //iPhoneのカメラによって返されるフォーマット + case TextureFormat.ATF_RGB_DXT1: break; //FlashでDXT1圧縮されたテクスチャフォーマット + case TextureFormat.ATF_RGBA_JPG: break; //FlashでJPG圧縮されたテクスチャフォーマット + case TextureFormat.ATF_RGB_JPG: break; //FlashでJPG圧縮されたテクスチャフォーマット +#if UNITY_WII + case TextureFormat.WiiCMPR: break; //1テクセル4ビットの圧縮されたテクスチャフォーマット。アルファは現在サポート されていない + case TextureFormat.WiiI4: break; //Wii 専用のテクスチャフォーマット + case TextureFormat.WiiI8: break; //Wii 専用のテクスチャフォーマット。明度が8ビット + case TextureFormat.WiiRGB565: break; //Wii 専用の赤(5 ビット)、緑(6 ビット)、青(5 ビット)のテクスチャフォーマット +#endif //UNITY_WII + default: //それ以外なら + result = true; //透過 + break; + } + } } return result; } From 76280c560920f40832f8cc88268b5910549e77e7 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Wed, 18 Sep 2013 00:59:01 +0900 Subject: [PATCH 26/37] =?UTF-8?q?PMXConverter:=E3=83=9E=E3=83=86=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=83=AB=E3=81=AE=E9=80=8F=E9=81=8E=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=81=AB=E6=9D=90=E8=B3=AA=E3=83=A2=E3=83=BC=E3=83=95=E3=82=92?= =?UTF-8?q?=E5=8F=82=E7=85=A7=E3=81=99=E3=82=8B=E6=A7=98=E3=81=AB=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/PMXConverter.cs | 54 ++++++++++++++++++++---- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 93e3f1a..29ba4ea 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -444,16 +444,52 @@ Material[][] CreateMaterials(MeshCreationInfo[] creation_info) /// マテリアル Material[] EntryAttributesForMaterials() { - return format_.material_list.material.Select(x=>ConvertMaterial(x)) - .ToArray(); + //材質モーフが透過を要望するか + bool[] is_transparent_by_material_morph = IsTransparentByMaterialMorph(); + + return Enumerable.Range(0, format_.material_list.material.Length) + .Select(x=>ConvertMaterial(format_.material_list.material[x], is_transparent_by_material_morph[x])) + .ToArray(); } + /// + /// 材質モーフに依る透過要望 + /// + /// 透過要望リスト + bool[] IsTransparentByMaterialMorph() + { + bool[] result = Enumerable.Repeat(false, format_.material_list.material.Length) + .ToArray(); + var transparent_material_indices = format_.morph_list.morph_data.Where(x=>PMXFormat.MorphData.MorphType.Material==x.morph_type) //材質モーフなら + .SelectMany(x=>x.morph_offset) //材質モーフオフセット取得 + .Select(x=>(PMXFormat.MaterialMorphOffset)x) //材質モーフオフセットにキャスト + .Where(x=>(PMXFormat.MaterialMorphOffset.OffsetMethod.Mul==x.offset_method)&&(x.diffuse.a < 1.0f)) //拡散色が透過に為るなら + .Select(x=>x.material_index) //マテリアルインデックス取得 + .Distinct(); //重複除去 + foreach (uint material_index in transparent_material_indices) { + //材質モーフに依って透過が要望されているなら + //透過扱いにする + if (material_index < (uint)format_.material_list.material.Length) { + //単体モーフのマテリアルインデックスなら + //対象マテリアルだけ透過扱い + result[material_index] = true; + } else { + //全対象モーフのマテリアルインデックスなら + //全て透過扱い + result = Enumerable.Repeat(true, result.Length).ToArray(); + break; + } + } + return result; + } + /// /// マテリアルをUnity用に変換する /// /// Unity用マテリアル /// PMX用マテリアル - Material ConvertMaterial(PMXFormat.Material material) + /// 強制透過 + Material ConvertMaterial(PMXFormat.Material material, bool is_force_transparent) { //先にテクスチャ情報を検索 Texture2D main_texture = null; @@ -464,7 +500,7 @@ Material ConvertMaterial(PMXFormat.Material material) } //マテリアルに設定 - Material result = new Material(Shader.Find(GetMmdShaderPath(material, main_texture))); + Material result = new Material(Shader.Find(GetMmdShaderPath(material, main_texture, is_force_transparent))); // シェーダに依って値が有ったり無かったりするが、設定してもエラーに為らない様なので全部設定 result.SetColor("_Color", material.diffuse_color); @@ -535,9 +571,10 @@ Material ConvertMaterial(PMXFormat.Material material) /// MMDシェーダーパス /// シェーダーを設定するマテリアル /// シェーダーに設定するメインテクスチャ - string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture) { + /// 強制透過 + string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture, bool is_force_transparent) { string result = "MMD/"; - if (IsTransparentMaterial(material, texture)) { + if (IsTransparentMaterial(material, texture, is_force_transparent)) { result += "Transparent/"; } result += "PMDMaterial"; @@ -564,8 +601,9 @@ string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture) { /// true:透過, false:不透明 /// シェーダーを設定するマテリアル /// シェーダーに設定するメインテクスチャ - bool IsTransparentMaterial(PMXFormat.Material material, Texture2D texture) { - bool result = false; + /// 強制透過 + bool IsTransparentMaterial(PMXFormat.Material material, Texture2D texture, bool is_force_transparent) { + bool result = is_force_transparent; //強制透過かの確認 result = result || (material.diffuse_color.a < 1.0f); //アルファ値が透過かの確認 if (null != texture) { result = result || texture.alphaIsTransparency; //alphaIsTransparencyフラグが透過かの確認 From 6eeced7f6bdd4700b4083f6277a4ee2cdb425a73 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 23 Nov 2013 20:30:12 +0900 Subject: [PATCH 27/37] =?UTF-8?q?PMXConverter:=E3=83=9E=E3=83=86=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=83=AB=E3=81=AE=E9=80=8F=E9=81=8E=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=81=AB=E3=83=86=E3=82=AF=E3=82=BB=E3=83=AB=E6=83=85=E5=A0=B1?= =?UTF-8?q?=E3=82=92=E5=8F=82=E7=85=A7=E3=81=99=E3=82=8B=E6=A7=98=E3=81=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MMDLoader/Private/AlphaReadableTexture.cs | 123 +++++++++ .../AlphaReadableTextureDirectoryImporter.cs | 28 ++ Editor/MMDLoader/Private/PMXConverter.cs | 243 +++++++++++++----- 3 files changed, 332 insertions(+), 62 deletions(-) create mode 100644 Editor/MMDLoader/Private/AlphaReadableTexture.cs create mode 100644 Editor/MMDLoader/Private/AlphaReadableTextureDirectoryImporter.cs diff --git a/Editor/MMDLoader/Private/AlphaReadableTexture.cs b/Editor/MMDLoader/Private/AlphaReadableTexture.cs new file mode 100644 index 0000000..ca5e0a5 --- /dev/null +++ b/Editor/MMDLoader/Private/AlphaReadableTexture.cs @@ -0,0 +1,123 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; + +public class AlphaReadableTexture : System.IDisposable { + + /// + /// コンストラクタ + /// + /// テクスチャ相対パスリスト + /// カレントディレクトリ("/"終わり、テクスチャの相対パス基点) + /// 解析作業用ディレクトリ("/"終わり、このディレクトリの下に解析作業用ディレクトリを作ります) + public AlphaReadableTexture(string[] texture_path_list, string current_directory, string temporary_directory) + { + texture_path_list_ = texture_path_list; + current_directory_ = current_directory; + temporary_directory_ = temporary_directory + directory_name + "/"; + + //テクスチャ作成 + foreach (string texture_path in texture_path_list_.Where(x=>!string.IsNullOrEmpty(x)).Distinct()) { + CreateReadableTexture(texture_path); + } + AssetDatabase.Refresh(); + //テクスチャ取得 + textures_ = texture_path_list_.Select(x=>GetReadableTexture(x)).ToArray(); + } + + /// + /// 読み込み可能テクスチャの取得 + /// + /// 読み込み可能テクスチャ + public Texture2D[] textures {get{return textures_;}} + + /// + /// Disposeインターフェース + /// + public void Dispose() + { + //テクスチャ破棄 + foreach (string texture_path in texture_path_list_.Where(x=>!string.IsNullOrEmpty(x)).Distinct()) { + DeleteReadableTexture(texture_path); + } + //ディレクトリの破棄 + string path = Application.dataPath + "/../" + temporary_directory_; //"Asset/"が被るので1階層上がる + if (System.IO.Directory.Exists(path)) { + System.IO.Directory.Delete(path, true); + } + } + + /// + /// 解析対象ディレクトリ名の取得 + /// + /// The directory_name. + public static string directory_name {get{return "AlphaReadableTextureDirectory.MmdForUnity";}} + + /// + /// 読み込み可能テクスチャの作成 + /// + /// テクスチャパス + private void CreateReadableTexture(string texture_path) + { + if (!string.IsNullOrEmpty(texture_path)) { + string base_texture_path = current_directory_ + texture_path; + string readable_texture_path = temporary_directory_ + texture_path; + CreateDirectoryPath(System.IO.Path.GetDirectoryName(readable_texture_path)); + bool is_copy_success = AssetDatabase.CopyAsset(base_texture_path, readable_texture_path); + if (!is_copy_success) { + throw new System.InvalidOperationException(); + } + } + } + + /// + /// 読み込み可能テクスチャの取得 + /// + /// 読み込み可能テクスチャ + /// テクスチャパス + private Texture2D GetReadableTexture(string texture_path) + { + Texture2D result = null; + if (!string.IsNullOrEmpty(texture_path)) { + string readable_texture_path = temporary_directory_ + texture_path; + result = (Texture2D)AssetDatabase.LoadAssetAtPath(readable_texture_path, typeof(Texture2D)); + } + return result; + } + + /// + /// 読み込み可能テクスチャの削除 + /// + /// テクスチャパス + private void DeleteReadableTexture(string texture_path) + { + if (!string.IsNullOrEmpty(texture_path)) { + string readable_texture_path = temporary_directory_ + texture_path; + AssetDatabase.DeleteAsset(readable_texture_path); + } + } + + /// + /// ディレクトリの作成(親ディレクトリが無ければ再帰的に作成) + /// + /// ディレクトリパス + private static void CreateDirectoryPath(string path) + { + //親ディレクトリ作成 + string parent_path = System.IO.Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(parent_path) && !System.IO.Directory.Exists(parent_path)) { + CreateDirectoryPath(parent_path); + } + //カレントディレクトリ作成 + if (!System.IO.Directory.Exists(path)) { + string name = System.IO.Path.GetFileName(path); + AssetDatabase.CreateFolder(parent_path, name); + } + } + + private Texture2D[] textures_; //読み込み可能テクスチャ + private string[] texture_path_list_; //解析するテクスチャリスト + private string current_directory_; //カレントディレクトリ + private string temporary_directory_; //解析作業用ディレクトリ +} diff --git a/Editor/MMDLoader/Private/AlphaReadableTextureDirectoryImporter.cs b/Editor/MMDLoader/Private/AlphaReadableTextureDirectoryImporter.cs new file mode 100644 index 0000000..97d0c2a --- /dev/null +++ b/Editor/MMDLoader/Private/AlphaReadableTextureDirectoryImporter.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; + +public class AlphaReadableTextureDirectoryImporter : AssetPostprocessor { + + /// + /// テクスチャプリプロセッサ + /// + void OnPreprocessTexture() { + if (-1 != assetPath.IndexOf(AlphaReadableTexture.directory_name)) { + //MmdForUnityの解析用ディレクトリなら + TextureImporter importer = (TextureImporter)assetImporter; + importer.isReadable = true; //読み込み可能とする + importer.textureFormat = TextureImporterFormat.Alpha8; //アルファのみ + importer.mipmapEnabled = false; //mipmapを作成しない + if (importer.DoesSourceTextureHaveAlpha()) { + //アルファが有れば + //透過フラグを立てる + importer.alphaIsTransparency = true; + } else { + //アルファが無ければ + //解像度を最小化 + importer.maxTextureSize = 1; + } + } + } +} diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 29ba4ea..df89b5f 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -6,7 +6,7 @@ namespace MMD { - public class PMXConverter + public class PMXConverter : System.IDisposable { /// /// GameObjectを作成する @@ -17,8 +17,11 @@ public class PMXConverter /// IKを使用するか /// スケール public static GameObject CreateGameObject(PMXFormat format, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { - PMXConverter converter = new PMXConverter(); - return converter.CreateGameObject_(format, use_rigidbody, use_mecanim, use_ik, scale); + GameObject result; + using (PMXConverter converter = new PMXConverter()) { + result = converter.CreateGameObject_(format, use_rigidbody, use_mecanim, use_ik, scale); + } + return result; } /// @@ -29,6 +32,16 @@ public static GameObject CreateGameObject(PMXFormat format, bool use_rigidbody, /// private PMXConverter() {} + /// + /// Disposeインターフェース + /// + public void Dispose() + { + if (null != alpha_readable_texture_) { + alpha_readable_texture_.Dispose(); + } + } + /// /// GameObjectを作成する /// @@ -425,6 +438,12 @@ void CreateAssetForMesh(Mesh mesh, int index) /// メッシュ作成情報 Material[][] CreateMaterials(MeshCreationInfo[] creation_info) { + // 適当なフォルダに投げる + string path = format_.meta_header.folder + "/Materials/"; + if (!System.IO.Directory.Exists(path)) { + AssetDatabase.CreateFolder(format_.meta_header.folder, "Materials"); + } + //全マテリアルを作成 Material[] materials = EntryAttributesForMaterials(); CreateAssetForMaterials(materials); @@ -445,17 +464,34 @@ Material[][] CreateMaterials(MeshCreationInfo[] creation_info) Material[] EntryAttributesForMaterials() { //材質モーフが透過を要望するか - bool[] is_transparent_by_material_morph = IsTransparentByMaterialMorph(); - + bool[] is_transparent_by_material = IsTransparentByMaterial(); //材質 + bool[] is_transparent_by_material_morph = IsTransparentByMaterialMorph(); //材質モーフ + bool[] is_transparent_by_texture_alpha = IsTransparentByTextureAlpha(); //テクスチャのアルファ値(UV考慮済み) + return Enumerable.Range(0, format_.material_list.material.Length) - .Select(x=>ConvertMaterial(format_.material_list.material[x], is_transparent_by_material_morph[x])) + .Select(x=>new {material = format_.material_list.material[x] + , is_transparent = is_transparent_by_material[x] || is_transparent_by_material_morph[x] || is_transparent_by_texture_alpha[x] + } + ) + .Select(x=>ConvertMaterial(x.material, x.is_transparent)) .ToArray(); } /// - /// 材質モーフに依る透過要望 + /// 材質に依る透過確認 + /// + /// 透過かの配列(true:透過, false:不透明) + bool[] IsTransparentByMaterial() + { + bool[] result = format_.material_list.material.Select(x=>x.diffuse_color.a < 1.0f) + .ToArray(); + return result; + } + + /// + /// 材質モーフに依る透過確認 /// - /// 透過要望リスト + /// 透過かの配列(true:透過, false:不透明) bool[] IsTransparentByMaterialMorph() { bool[] result = Enumerable.Repeat(false, format_.material_list.material.Length) @@ -482,14 +518,132 @@ bool[] IsTransparentByMaterialMorph() } return result; } - + + /// + /// テクスチャのアルファ値に依る透過確認 + /// + /// 透過かの配列(true:透過, false:不透明) + bool[] IsTransparentByTextureAlpha() + { + Texture2D[] textures = GetTextureList(); + Vector2[][] uvs = CreateMeshCreationInfoPacks().Select(x=>x.plane_indices.Select(y=>format_.vertex_list.vertex[y].uv).ToArray()) //頂点インデックスをUV値に変換 + .ToArray(); + bool[] result = Enumerable.Range(0, format_.material_list.material.Length) + .Select(x=>((null != textures[x]) + ? IsTransparentByTextureAlphaWithUv(textures[x], uvs[x]) + : false + )) + .ToArray(); + return result; + } + + /// + /// テクスチャの取得 + /// + /// テクスチャ配列 + Texture2D[] GetTextureList() + { + string[] texture_path = format_.material_list.material.Select(x=>x.usually_texture_index) //材質が使用しているテクスチャインデックスを取得 + .Select(x=>((x + /// UV値を考慮したテクスチャのアルファ値に依る透過確認 + /// + /// 透過か(true:透過, false:不透明) + /// テクスチャ + /// UV値(3つ単位で三角形を構成する) + static bool IsTransparentByTextureAlphaWithUv(Texture2D texture, Vector2[] uvs) + { + bool result = true; + if (TextureFormat.Alpha8 == texture.format) { + //ファイルがDDS以外なら(AlphaReadableTextureDirectoryImporterに依ってDDS以外はAlpha8に為る) + //alphaIsTransparencyを確認する + result = texture.alphaIsTransparency; //アルファ値を持たないなら透過フラグが立っていない + } + if (result) { + //アルファ値を持つなら + //詳細確認 + result = Enumerable.Range(0, uvs.Length / 3) //3つ単位で取り出す為の元インデックス + .Select(x=>x*3) //3つ間隔に変換 + .Any(x=>IsTransparentByTextureAlphaWithUv(texture, uvs[x+0],uvs[x+1],uvs[x+2])); //三角形を透過確認、どれかが透過していたら透過とする + } + return result; + } + + /// + /// UV値を考慮したテクスチャのアルファ値に依る透過確認 + /// + /// 透過か(true:透過, false:不透明) + /// テクスチャ + /// 三角形頂点のUV値 + /// 三角形頂点のUV値 + /// 三角形頂点のUV値 + /// + /// 理想ならば全テクセルを確認しなければならないが、 + /// 現在の実装では三角形を構成する各頂点のUV・重心・各辺の中心点の7点のテクセルしか確認していない + /// + static bool IsTransparentByTextureAlphaWithUv(Texture2D texture, Vector2 uv1, Vector2 uv2, Vector2 uv3) + { + bool result = true; //透過 + do { + //座標系が相違しているので補正 + uv1.Set(uv1.x, 1.0f - uv1.y - (1.0f / texture.height)); + uv2.Set(uv2.x, 1.0f - uv2.y - (1.0f / texture.height)); + uv3.Set(uv3.x, 1.0f - uv3.y - (1.0f / texture.height)); + + const float c_threshold = 253.0f / 255.0f; //253程度迄は不透明として見逃す + + //頂点直下 + if (texture.GetPixelBilinear(uv1.x, uv1.y).a < c_threshold) { + break; + } + if (texture.GetPixelBilinear(uv2.x, uv2.y).a < c_threshold) { + break; + } + if (texture.GetPixelBilinear(uv3.x, uv3.y).a < c_threshold) { + break; + } + + //重心 + Vector2 center = new Vector2((uv1.x + uv2.x + uv3.x) / 3.0f, (uv1.y + uv2.y + uv3.y) / 3.0f); + if (texture.GetPixelBilinear(center.x, center.y).a < c_threshold) { + break; + } + + //辺中央 + Vector2 uv12 = new Vector2((uv1.x + uv2.x) / 2.0f, (uv1.y + uv2.y) / 2.0f); + if (texture.GetPixelBilinear(uv12.x, uv12.y).a < c_threshold) { + break; + } + Vector2 uv23 = new Vector2((uv2.x + uv3.x) / 2.0f, (uv2.y + uv3.y) / 2.0f); + if (texture.GetPixelBilinear(uv23.x, uv23.y).a < c_threshold) { + break; + } + Vector2 uv31 = new Vector2((uv3.x + uv1.x) / 2.0f, (uv3.y + uv1.y) / 2.0f); + if (texture.GetPixelBilinear(uv31.x, uv31.y).a < c_threshold) { + break; + } + + //此処迄来たら不透明 + result = false; + } while(false); + return result; + } + /// /// マテリアルをUnity用に変換する /// /// Unity用マテリアル /// PMX用マテリアル - /// 強制透過 - Material ConvertMaterial(PMXFormat.Material material, bool is_force_transparent) + /// 透過か + Material ConvertMaterial(PMXFormat.Material material, bool is_transparent) { //先にテクスチャ情報を検索 Texture2D main_texture = null; @@ -500,7 +654,8 @@ Material ConvertMaterial(PMXFormat.Material material, bool is_force_transparent) } //マテリアルに設定 - Material result = new Material(Shader.Find(GetMmdShaderPath(material, main_texture, is_force_transparent))); + string shader_path = GetMmdShaderPath(material, main_texture, is_transparent); + Material result = new Material(Shader.Find(shader_path)); // シェーダに依って値が有ったり無かったりするが、設定してもエラーに為らない様なので全部設定 result.SetColor("_Color", material.diffuse_color); @@ -571,10 +726,10 @@ Material ConvertMaterial(PMXFormat.Material material, bool is_force_transparent) /// MMDシェーダーパス /// シェーダーを設定するマテリアル /// シェーダーに設定するメインテクスチャ - /// 強制透過 - string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture, bool is_force_transparent) { + /// 透過か + string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture, bool is_transparent) { string result = "MMD/"; - if (IsTransparentMaterial(material, texture, is_force_transparent)) { + if (IsTransparentMaterial(is_transparent)) { result += "Transparent/"; } result += "PMDMaterial"; @@ -599,42 +754,9 @@ string GetMmdShaderPath(PMXFormat.Material material, Texture2D texture, bool is_ /// 透過マテリアル確認 /// /// true:透過, false:不透明 - /// シェーダーを設定するマテリアル - /// シェーダーに設定するメインテクスチャ - /// 強制透過 - bool IsTransparentMaterial(PMXFormat.Material material, Texture2D texture, bool is_force_transparent) { - bool result = is_force_transparent; //強制透過かの確認 - result = result || (material.diffuse_color.a < 1.0f); //アルファ値が透過かの確認 - if (null != texture) { - result = result || texture.alphaIsTransparency; //alphaIsTransparencyフラグが透過かの確認 - if (!result) { - //テクスチャフォーマットから透過かの確認 - switch (texture.format) { - case TextureFormat.RGB24: break; //各色が8 ビットのテクスチャフォーマット - case TextureFormat.RGB565: break; //赤(5ビット)、緑(6ビット)、青(5ビット)のテクスチャフォーマット - case TextureFormat.DXT1: break; //圧縮されたテクスチャフォーマット - case TextureFormat.PVRTC_RGB2: break; //1ピクセル2ビットの圧縮されたテクスチャフォーマット(iOS 専用) - case TextureFormat.PVRTC_RGB4: break; //1ピクセル4ビットの圧縮されたテクスチャフォーマット(iOS 専用) - case TextureFormat.ETC_RGB4: break; //1ピクセル4ビットの圧縮されたテクスチャフォーマット(OpenGL ES 2.0 専用) - case TextureFormat.ATC_RGB4: break; //1ピクセル4ビットの圧縮されたテクスチャフォーマット(ATITC専用) - case TextureFormat.ATC_RGBA8: break; //1ピクセル8ビットの圧縮されたテクスチャフォーマット(ATITC専用) - case TextureFormat.BGRA32: break; //iPhoneのカメラによって返されるフォーマット - case TextureFormat.ATF_RGB_DXT1: break; //FlashでDXT1圧縮されたテクスチャフォーマット - case TextureFormat.ATF_RGBA_JPG: break; //FlashでJPG圧縮されたテクスチャフォーマット - case TextureFormat.ATF_RGB_JPG: break; //FlashでJPG圧縮されたテクスチャフォーマット -#if UNITY_WII - case TextureFormat.WiiCMPR: break; //1テクセル4ビットの圧縮されたテクスチャフォーマット。アルファは現在サポート されていない - case TextureFormat.WiiI4: break; //Wii 専用のテクスチャフォーマット - case TextureFormat.WiiI8: break; //Wii 専用のテクスチャフォーマット。明度が8ビット - case TextureFormat.WiiRGB565: break; //Wii 専用の赤(5 ビット)、緑(6 ビット)、青(5 ビット)のテクスチャフォーマット -#endif //UNITY_WII - default: //それ以外なら - result = true; //透過 - break; - } - } - } - return result; + /// 透過か + bool IsTransparentMaterial(bool is_transparent) { + return is_transparent; } /// @@ -712,12 +834,8 @@ bool IsNoReceiveShadowMaterial(PMXFormat.Material material) { /// /// 対象マテリアル void CreateAssetForMaterials(Material[] materials) { - // 適当なフォルダに投げる string path = format_.meta_header.folder + "/Materials/"; - if (!System.IO.Directory.Exists(path)) { - AssetDatabase.CreateFolder(format_.meta_header.folder, "Materials"); - } - + for (int i = 0, i_max = materials.Length; i < i_max; ++i) { string name = GetFilePathString(format_.material_list.material[i].name); string file_name = path + i.ToString() + "_" + name + ".asset"; @@ -1807,11 +1925,12 @@ private static string GetFilePathString(string src) { const uint c_max_vertex_count_in_mesh = 65535; //meshに含まれる最大頂点数(Unity3D的には65536迄入ると思われるが、ushort.MaxValueは特別な値として使うのでその分を除外) - GameObject root_game_object_; - PMXFormat format_; - bool use_rigidbody_; - bool use_mecanim_; - bool use_ik_; - float scale_; + GameObject root_game_object_; + PMXFormat format_; + bool use_rigidbody_; + bool use_mecanim_; + bool use_ik_; + float scale_; + AlphaReadableTexture alpha_readable_texture_ = null; } } From abc481129219ce2f82db6f4490a89546a5920642 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 21 Dec 2013 18:06:26 +0900 Subject: [PATCH 28/37] =?UTF-8?q?=E3=82=A8=E3=83=83=E3=82=B8=E4=BB=98?= =?UTF-8?q?=E3=81=8D=E6=9D=90=E8=B3=AA=E3=81=8C=E5=8D=8A=E9=80=8F=E6=98=8E?= =?UTF-8?q?=E3=82=BD=E3=83=BC=E3=83=88=E3=82=92=E7=84=A1=E8=A6=96=E3=81=99?= =?UTF-8?q?=E3=82=8B=E4=B8=8D=E5=85=B7=E5=90=88=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader | 3 +-- .../Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader | 3 +-- .../Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader | 2 +- .../PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader index d640519..0192079 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack-NoCastShadow.shader @@ -37,8 +37,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-CullBack-NoCastShadow" // Settings Tags { - // JUST After Transparent - "Queue" = "Transparent+1" + "Queue" = "Transparent" "RenderType" = "Transparent" } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader index 372464b..0c30e15 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-CullBack.shader @@ -37,8 +37,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-CullBack" // Settings Tags { - // JUST After Transparent - "Queue" = "Transparent+1" + "Queue" = "Transparent" "RenderType" = "Transparent" } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader index 5c4f10a..2aa00e5 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans-NoCastShadow.shader @@ -37,7 +37,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline-NoCastShadow" // Settings Tags { - "Queue" = "Transparent+1" + "Queue" = "Transparent" "RenderType" = "Transparent" } diff --git a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader index d1a21b5..7cfdaaa 100644 --- a/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader +++ b/Resources/PMDMaterial/Shaders/MeshPmdMaterialOutline-Trans.shader @@ -37,8 +37,7 @@ Shader "MMD/Transparent/PMDMaterial-with-Outline" // Settings Tags { - // JUST After Transparent - "Queue" = "Transparent+1" + "Queue" = "Transparent" "RenderType" = "Transparent" } From 0e3bffe9b29fb770d36c98d2462e02ada13ac7c0 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Mon, 25 Nov 2013 05:10:40 +0900 Subject: [PATCH 29/37] =?UTF-8?q?PMXConverter:=E3=83=9E=E3=83=86=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=83=AB=E3=81=AE=E9=80=8F=E9=81=8E=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=81=ABUV=E3=83=A2=E3=83=BC=E3=83=95=E3=82=92=E5=8F=82?= =?UTF-8?q?=E7=85=A7=E3=81=99=E3=82=8B=E6=A7=98=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/PMXConverter.cs | 83 ++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index df89b5f..56aa578 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -526,8 +526,7 @@ bool[] IsTransparentByMaterialMorph() bool[] IsTransparentByTextureAlpha() { Texture2D[] textures = GetTextureList(); - Vector2[][] uvs = CreateMeshCreationInfoPacks().Select(x=>x.plane_indices.Select(y=>format_.vertex_list.vertex[y].uv).ToArray()) //頂点インデックスをUV値に変換 - .ToArray(); + Vector2[][] uvs = GetUvList(); bool[] result = Enumerable.Range(0, format_.material_list.material.Length) .Select(x=>((null != textures[x]) ? IsTransparentByTextureAlphaWithUv(textures[x], uvs[x]) @@ -554,7 +553,83 @@ Texture2D[] GetTextureList() } /// - /// UV値を考慮したテクスチャのアルファ値に依る透過確認 + /// UVの取得 + /// + /// UV配列 + /// + /// UVモーフにて改変される場合は未適応(0.0f)と全適応(1.0f)の2段階のみを扱い、中間適応は考慮しない。 + /// 複数のUVモーフが同一頂点に掛かる場合に多重適応すると単体では参照出来無い領域迄参照出来る様に為るが、これは考慮しない。 + /// 同様にグループモーフに依る1.0f超えも考慮しない。 + /// + Vector2[][] GetUvList() + { + uint[][] vertex_list = CreateMeshCreationInfoPacks().Select(x=>x.plane_indices).ToArray(); + + Dictionary[] uv_morphs = format_.morph_list.morph_data + .Where(x=>PMXFormat.MorphData.MorphType.Uv==x.morph_type) //UVモーフなら + .Select(x=>x.morph_offset.Select(y=>(PMXFormat.UVMorphOffset)y) + .ToDictionary(z=>z.vertex_index, z=>z.uv_offset) //頂点インデックスでディクショナリ化 + ) //UVモーフオフセット取得 + .ToArray(); + + List[] result = vertex_list.Select(x=>x.Select(y=>format_.vertex_list.vertex[y].uv).ToList()).ToArray(); + + //材質走査 + bool is_cancel = false; + for (int material_index = 0, material_index_max = result.Length; material_index < material_index_max; ++material_index) { + //UVモーフ走査 + for (int uv_morph_index = 0, uv_morph_index_max = uv_morphs.Length; uv_morph_index < uv_morph_index_max; ++uv_morph_index) { + var uv_morph = uv_morphs[uv_morph_index]; + //ブログレスパー更新 + is_cancel = EditorUtility.DisplayCancelableProgressBar("Create UV Area Infomation" + , "Material:[" + material_index + "|" + material_index_max + "]" + + format_.material_list.material[material_index].name + + "\t" + + "UV Morph:[" + uv_morph_index + "|" + uv_morph_index_max + "]" + + format_.morph_list.morph_data.Where(x=>PMXFormat.MorphData.MorphType.Uv==x.morph_type).Skip(uv_morph_index).First().morph_name + , ((((float)uv_morph_index / (float)uv_morph_index_max) + (float)material_index) / (float)material_index_max) + ); + if (is_cancel) { + break; + } + + //先行UVモーフ対象確認(三角形構成を無視して全頂点をUVモーフ参照) + var vertex_dictionary = vertex_list[material_index].Distinct().ToDictionary(x=>x, x=>true); //(UVモーフに設定されている頂点数依りも三角形構成頂点の方が多いと思うので、そちら側をlogNにする為に辞書作成) + if (uv_morph.Keys.Any(x=>vertex_dictionary.ContainsKey(x))) { + //UVモーフ対象なら + //頂点走査(三角形構成頂点走査) + for (int vertex_index = 0, vertex_index_max = vertex_list[material_index].Length; vertex_index < vertex_index_max; vertex_index+=3) { + //三角形構成頂点インデックス取り出し + uint[] tri_vertices = new []{vertex_list[material_index][vertex_index+0] + , vertex_list[material_index][vertex_index+1] + , vertex_list[material_index][vertex_index+2] + }; + //UVモーフ対象確認 + if (tri_vertices.Any(x=>uv_morph.ContainsKey(x))) { + //UVモーフ対象なら + //適応したUV値を作成 + var tri_uv = tri_vertices.Select(x=>new{original_uv = format_.vertex_list.vertex[x].uv + , add_uv = ((uv_morph.ContainsKey(x))? uv_morph[x]: Vector4.zero) + } + ) + .Select(x=>new Vector2(x.original_uv.x + x.add_uv.x, x.original_uv.y + x.add_uv.y)); + //追加 + result[material_index].AddRange(tri_uv); + } + } + } + } + if (is_cancel) { + break; + } + } + EditorUtility.ClearProgressBar(); + + return result.Select(x=>x.ToArray()).ToArray(); + } + + /// + /// UV値を考慮した、テクスチャのアルファ値に依る透過確認 /// /// 透過か(true:透過, false:不透明) /// テクスチャ @@ -578,7 +653,7 @@ static bool IsTransparentByTextureAlphaWithUv(Texture2D texture, Vector2[] uvs) } /// - /// UV値を考慮したテクスチャのアルファ値に依る透過確認 + /// UV値を考慮した、テクスチャのアルファ値に依る透過確認 /// /// 透過か(true:透過, false:不透明) /// テクスチャ From c79ec17b35c8e0c8f6c1789f78834d306ea82533 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 7 Dec 2013 17:56:42 +0900 Subject: [PATCH 30/37] =?UTF-8?q?PMXConverter:=E3=83=9E=E3=83=86=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=83=AB=E3=81=AE=E9=80=8F=E9=81=8E=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=81=AB=E3=82=A8=E3=83=83=E3=82=B8=E3=81=AE=E9=80=8F=E9=81=8E?= =?UTF-8?q?=E3=82=92=E8=80=83=E6=85=AE=E3=81=99=E3=82=8B=E6=A7=98=E3=81=AB?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/PMXConverter.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 56aa578..e650f0e 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -483,7 +483,8 @@ Material[] EntryAttributesForMaterials() /// 透過かの配列(true:透過, false:不透明) bool[] IsTransparentByMaterial() { - bool[] result = format_.material_list.material.Select(x=>x.diffuse_color.a < 1.0f) + //拡散色とエッジ色の透過確認 + bool[] result = format_.material_list.material.Select(x=>(x.diffuse_color.a < 1.0f) || (x.edge_color.a < 1.0f)) .ToArray(); return result; } @@ -499,7 +500,7 @@ bool[] IsTransparentByMaterialMorph() var transparent_material_indices = format_.morph_list.morph_data.Where(x=>PMXFormat.MorphData.MorphType.Material==x.morph_type) //材質モーフなら .SelectMany(x=>x.morph_offset) //材質モーフオフセット取得 .Select(x=>(PMXFormat.MaterialMorphOffset)x) //材質モーフオフセットにキャスト - .Where(x=>(PMXFormat.MaterialMorphOffset.OffsetMethod.Mul==x.offset_method)&&(x.diffuse.a < 1.0f)) //拡散色が透過に為るなら + .Where(x=>(PMXFormat.MaterialMorphOffset.OffsetMethod.Mul==x.offset_method)&&((x.diffuse.a < 1.0f)||(x.edge_color.a < 1.0f))) //拡散色かエッジ色が透過に為るなら .Select(x=>x.material_index) //マテリアルインデックス取得 .Distinct(); //重複除去 foreach (uint material_index in transparent_material_indices) { From b2c2292df0981f348c0e107699d8d2d7eab2f0fe Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sat, 30 Nov 2013 08:08:40 +0900 Subject: [PATCH 31/37] =?UTF-8?q?=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0?= =?UTF-8?q?=E3=83=AC=E3=83=B3=E3=83=80=E3=83=BC=E3=82=AD=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 初期値は無効化されているので、エディタ上で有効化する。 --- Editor/MMDEngineEditor.cs | 109 ++++++++++++++++++++++- Editor/MMDLoader/Private/PMXConverter.cs | 27 ++++-- Resources/MMDEngine.cs | 2 + 3 files changed, 129 insertions(+), 9 deletions(-) diff --git a/Editor/MMDEngineEditor.cs b/Editor/MMDEngineEditor.cs index dc1f1fa..01934f0 100644 --- a/Editor/MMDEngineEditor.cs +++ b/Editor/MMDEngineEditor.cs @@ -37,7 +37,8 @@ public override void OnInspectorGUI() is_dirty = OnInspectorGUIforUseRigidbody() || is_dirty; is_dirty = OnInspectorGUIforIkList() || is_dirty; is_dirty = OnInspectorGUIforShaderList() || is_dirty; - + is_dirty = OnInspectorGUIforRenderQueue() || is_dirty; + if (is_dirty) { //更新が有ったなら //Inspector更新 @@ -215,7 +216,9 @@ private bool OnInspectorGUIforShaderList() , new {flag=ShaderFlag.Hidden, reverse=false} }; //マテリアル - foreach (var material in materials) { + for (int i = 0, i_max = materials.Length; i < i_max; ++i) { + Material material = materials[i]; + EditorGUILayout.BeginHorizontal(); { //ラベル @@ -256,7 +259,8 @@ private bool OnInspectorGUIforShaderList() Undo.RegisterUndo(material, "Shader Change"); #endif - SetShader(material, flag); + int render_queue = ((self.enable_render_queue)? self.render_queue_value + i: -1); + SetShader(material, flag, render_queue); is_update = true; } } @@ -269,6 +273,92 @@ private bool OnInspectorGUIforShaderList() return is_update; } + /// + /// カスタムレンダーキューの為のInspector描画 + /// + /// 更新が有ったか(true:更新有り, false:未更新) + private bool OnInspectorGUIforRenderQueue() + { + MMDEngine self = (MMDEngine)target; + bool is_update = false; + +#if !MFU_DISABLE_LEGACY_DATA_SUPPORT + if ((false == self.enable_render_queue) && (0 == self.render_queue_value)) { + //カスタムレンダーキュー関連が設定されていないなら(昔の変換データ) + //無効状態で初期化 + self.enable_render_queue = false; + const int c_render_queue_transparent = 3000; + self.render_queue_value = c_render_queue_transparent; + } +#endif + + bool enable_render_queue = self.enable_render_queue; + enable_render_queue = EditorGUILayout.Toggle("Render Queue", enable_render_queue); + if (self.enable_render_queue != enable_render_queue) { + //変更が掛かったなら + is_update = true; + } + int render_queue_value = -1; + if (enable_render_queue) { + //有効なら + render_queue_value = self.render_queue_value; + render_queue_value = EditorGUILayout.IntField("Render Queue Value", render_queue_value); + if (self.render_queue_value != render_queue_value) { + //変更が掛かったなら + is_update = true; + } + } + + if (is_update) { + //変更が掛かったなら + Material[] materials = GetMaterials(self); + //Undo登録 + var record_objects = materials.Select(x=>(UnityEngine.Object)x) //マテリアル全てと + .Concat(new UnityEngine.Object[]{self}) //UnityEngine + .ToArray(); +#if !UNITY_4_2 //4.3以降 + Undo.RecordObjects(record_objects, "Render Queue Change"); +#else + Undo.RegisterUndo(record_objects, "Render Queue Change"); +#endif + //更新 + self.enable_render_queue = enable_render_queue; + if (enable_render_queue) { + //有効化 + self.render_queue_value = render_queue_value; + for (int i = 0, i_max = materials.Length; i < i_max; ++i) { + var material = materials[i]; + ShaderFlag flag = AnalyzeShaderFlag(material); + if (0 != (flag & ShaderFlag.MmdShader)) { + //Mmdシェーダーなら + //カスタムレンダーキュー + if (0 != (flag & ShaderFlag.Transparent)) { + //透過なら + //マテリアル順にカスタムレンダーキューを設定 + material.renderQueue = render_queue_value + i; + } else { + //不透明なら + //カスタムレンダーキューを解除 + material.renderQueue = -1; + } + } + } + } else { + //無効化 + foreach (var material in materials) { + ShaderFlag flag = AnalyzeShaderFlag(material); + if (0 != (flag & ShaderFlag.MmdShader)) { + //Mmdシェーダーなら + //カスタムレンダーキューを解除 + material.renderQueue = -1; + } + } + } + } + + return is_update; + } + /// /// MMDシェーダー確認 /// @@ -357,7 +447,8 @@ static ShaderFlag AnalyzeShaderFlag(Material material) { /// /// マテリアル /// シェーダーフラグ - static void SetShader(Material material, ShaderFlag flag) { + /// 透過の場合に設定するレンダーキュー + static void SetShader(Material material, ShaderFlag flag, int render_queue) { if (0 != (flag & ShaderFlag.MmdShader)) { //Mmdシェーダーなら material.shader = CreateShaderFromShaderFlag(flag); @@ -371,6 +462,16 @@ static void SetShader(Material material, ShaderFlag flag) { float original_shader_type = (float)(int)flag; material.SetFloat("_DummyOriginalShaderType", original_shader_type); material.SetColor("_DummyColor", new Color(1.0f, 0.0f, 1.0f, 1.0f)); + } + //カスタムレンダーキュー + if (0 != (flag & ShaderFlag.Transparent)) { + //透過なら + //マテリアル順にカスタムレンダーキューを設定 + material.renderQueue = render_queue; + } else { + //不透明なら + //カスタムレンダーキューを解除 + material.renderQueue = -1; } } } diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index e650f0e..77461e2 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -62,6 +62,9 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool engine.scale = scale_; engine.outline_width = 1.0f; engine.material_outline_widths = format.material_list.material.Select(x=>x.edge_size).ToArray(); + engine.enable_render_queue = false; //初期値無効 + const int c_render_queue_transparent = 3000; + engine.render_queue_value = c_render_queue_transparent; MeshCreationInfo[] creation_info = CreateMeshCreationInfo(); // メッシュを作成する為の情報を作成 Mesh[] mesh = CreateMesh(creation_info); // メッシュの生成・設定 @@ -469,11 +472,11 @@ Material[] EntryAttributesForMaterials() bool[] is_transparent_by_texture_alpha = IsTransparentByTextureAlpha(); //テクスチャのアルファ値(UV考慮済み) return Enumerable.Range(0, format_.material_list.material.Length) - .Select(x=>new {material = format_.material_list.material[x] + .Select(x=>new {material_index = (uint)x , is_transparent = is_transparent_by_material[x] || is_transparent_by_material_morph[x] || is_transparent_by_texture_alpha[x] } ) - .Select(x=>ConvertMaterial(x.material, x.is_transparent)) + .Select(x=>ConvertMaterial(x.material_index, x.is_transparent)) .ToArray(); } @@ -717,10 +720,12 @@ static bool IsTransparentByTextureAlphaWithUv(Texture2D texture, Vector2 uv1, Ve /// マテリアルをUnity用に変換する /// /// Unity用マテリアル - /// PMX用マテリアル + /// PMX用マテリアルインデックス /// 透過か - Material ConvertMaterial(PMXFormat.Material material, bool is_transparent) + Material ConvertMaterial(uint material_index, bool is_transparent) { + PMXFormat.Material material = format_.material_list.material[material_index]; + //先にテクスチャ情報を検索 Texture2D main_texture = null; if (material.usually_texture_index < format_.texture_list.texture_file.Length) { @@ -743,7 +748,19 @@ Material ConvertMaterial(PMXFormat.Material material, bool is_transparent) const float c_default_scale = 0.085f; //0.085fの時にMMDと一致する様にしているので、それ以外なら補正 result.SetFloat("_OutlineWidth", material.edge_size * scale_ / c_default_scale); result.SetColor("_OutlineColor", material.edge_color); - + //カスタムレンダーキュー + { + MMDEngine engine = root_game_object_.GetComponent(); + if (engine.enable_render_queue && IsTransparentMaterial(is_transparent)) { + //カスタムレンダーキューが有効 かつ マテリアルが透過なら + //マテリアル順に並べる + result.renderQueue = engine.render_queue_value + (int)material_index; + } else { + //非透明なら + result.renderQueue = -1; + } + } + // スフィアテクスチャ if (material.sphere_texture_index < format_.texture_list.texture_file.Length) { string sphere_texture_file_name = format_.texture_list.texture_file[material.sphere_texture_index]; diff --git a/Resources/MMDEngine.cs b/Resources/MMDEngine.cs index 7a4b231..62e7763 100644 --- a/Resources/MMDEngine.cs +++ b/Resources/MMDEngine.cs @@ -13,6 +13,8 @@ public class MMDEngine : MonoBehaviour { #if UNITY_EDITOR public float outline_width; //エッジ幅係数(エディタ用) public float[] material_outline_widths; //材質のエッジ幅(エディタ用) + public bool enable_render_queue; //カスタムレンダーキューの使用 + public int render_queue_value; //カスタムレンダーキュー値 #endif // 訳があってこうなってる From 51778d96f794e18805936ff5701c1acc9f2706b6 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sun, 29 Dec 2013 02:31:03 +0900 Subject: [PATCH 32/37] =?UTF-8?q?AvatarSettingScript:=E8=85=95=E6=B0=B4?= =?UTF-8?q?=E5=B9=B3=E5=8C=96=E3=81=AB=E6=96=BC=E3=81=84=E3=81=A6=E3=80=81?= =?UTF-8?q?=E9=96=93=E6=8E=A5=E3=81=8C=E6=AD=A3=E3=81=97=E3=81=8F=E9=81=B8?= =?UTF-8?q?=E6=8A=9E=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E5=A0=B4=E5=90=88?= =?UTF-8?q?=E3=81=8C=E3=81=82=E3=82=8B=E4=B8=8D=E5=85=B7=E5=90=88=E3=81=AE?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MMDLoader/Private/AvatarSettingScript.cs | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index af47955..a334669 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -84,19 +84,20 @@ void SetRequirePose() } /// - /// 対象のボーンの中からより深く枝分かれする子ボーンを選び出す - /// 剛体用ボーンじゃないきちんとしたボーンを選び出すために使う + /// 特定の名前を持つボーンを先代から選び出す /// - /// 対象のボーン - /// さらに枝分かれする子ボーン - Transform SelectBranchedChildWhereManyChildren(Transform transform) + /// 基点のボーン + /// 対象のボーン名 + /// 対象の先代ボーン + /// + /// 基点ボーンが探索名なら基点ボーンを返す。 + /// + static Transform FindTransformUpwards(Transform transform, string name) { - Transform[] children = new Transform[transform.childCount]; - if (children.Length <= 0) Debug.LogError(transform.name + "の子がないので落ちるのです!"); - for (int i = 0; i < transform.childCount; i++) - children[i] = transform.GetChild(i); - int max = children.Max(x => x.childCount); - return children.Where(x => x.childCount == max).First(); + while ((null != transform) && (transform.name != name)) { + transform = transform.parent; + } + return transform; } /// @@ -104,7 +105,7 @@ Transform SelectBranchedChildWhereManyChildren(Transform transform) /// /// 対象のボーン /// Z軸のみを回転させるQuaternion - Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) + static Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) { // ボーンの向きを取得 var bone_vector = child_transform.position - transform.position; @@ -122,14 +123,17 @@ Quaternion ResetHorizontalPose(Transform transform, Transform child_transform) } /// - /// 腕全体を平行にする処理 + /// 腕全体を水平にする処理 /// - /// 肩ボーン - void StartResettingHorizontal(Transform shoulder) + /// 手首ボーン + /// ひじボーン名 + /// 腕ボーン名 + /// 肩ボーン名 + static void StartResettingHorizontal(Transform wrist, string hinge_name, string arm_name, string shoulder_name) { - var arm = SelectBranchedChildWhereManyChildren(shoulder); - var hinge = SelectBranchedChildWhereManyChildren(arm); - var wrist = SelectBranchedChildWhereManyChildren(hinge); + var hinge = FindTransformUpwards(wrist, hinge_name); + var arm = FindTransformUpwards(hinge, arm_name); + var shoulder = FindTransformUpwards(arm, shoulder_name); shoulder.transform.localRotation = ResetHorizontalPose(shoulder, arm); arm.transform.localRotation = ResetHorizontalPose(arm, hinge); hinge.transform.localRotation = ResetHorizontalPose(hinge, wrist); @@ -142,9 +146,11 @@ void StartResettingHorizontal(Transform shoulder) void SetRequirePose(Transform transform) { switch (transform.name) { - case "左肩": goto case "右肩"; - case "右肩": //Tポーズにする為に腕を持ち上げる - StartResettingHorizontal(transform); + case "左手首": //Tポーズにする為に腕を持ち上げる + StartResettingHorizontal(transform, "左ひじ", "左腕", "左肩"); + break; + case "右手首": //Tポーズにする為に腕を持ち上げる + StartResettingHorizontal(transform, "右ひじ", "右腕", "右肩"); break; case "腰": goto case "センター"; case "センター": From 7f8a9b5dad7155399bbdd71d9e44547eda757245 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sun, 29 Dec 2013 02:36:21 +0900 Subject: [PATCH 33/37] =?UTF-8?q?AvatarSettingScript:=E3=83=9C=E3=83=BC?= =?UTF-8?q?=E3=83=B3=E5=AD=98=E5=9C=A8=E7=A2=BA=E8=AA=8D=E3=81=AB=E6=96=BC?= =?UTF-8?q?=E3=81=84=E3=81=A6=E3=82=B7=E3=83=A7=E3=83=BC=E3=83=88=E3=82=AB?= =?UTF-8?q?=E3=83=83=E3=83=88=E3=82=92=E5=8A=B9=E3=81=8F=E6=A7=98=E3=81=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/Private/AvatarSettingScript.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index a334669..9c5c273 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -178,8 +178,7 @@ void SetRequirePose(Transform transform) /// true:ボーンが存在する, false:ボーンが存在しない /// ボーン名 bool HasBone(string name) { - int count = bones_.Where(x=>x.name == name).Count(); - return 0 < count; + return bones_.Any(x=>x.name == name); } /// From 3948cc27706d5181e373b313ce1bdabc24723d60 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Sun, 29 Dec 2013 05:17:15 +0900 Subject: [PATCH 34/37] =?UTF-8?q?AvatarSettingScript:=E8=85=B0=E3=83=9C?= =?UTF-8?q?=E3=83=BC=E3=83=B3=E3=81=A8=E3=81=97=E3=81=A6=E3=82=BB=E3=83=B3?= =?UTF-8?q?=E3=82=BF=E3=83=BC=E3=82=92=E7=94=A8=E3=81=84=E3=81=9F=E5=A0=B4?= =?UTF-8?q?=E5=90=88=E3=81=ABSkeletonBone=E3=81=AB=E8=85=B0=E3=83=9C?= =?UTF-8?q?=E3=83=BC=E3=83=B3=E3=81=AE=E8=A6=AA=E3=83=9C=E3=83=BC=E3=83=B3?= =?UTF-8?q?=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E6=83=85=E5=A0=B1=E3=81=8C?= =?UTF-8?q?=E4=B8=8D=E8=B6=B3=E3=81=99=E3=82=8B=E4=B8=8D=E5=85=B7=E5=90=88?= =?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MMDLoader/Private/AvatarSettingScript.cs | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index af47955..242ad50 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -287,15 +287,32 @@ HumanBone[] CreateHumanBone() /// スケルトンボーン SkeletonBone[] CreateSkeletonBone() { - return bones_.Select(x=>{ - SkeletonBone skeleton_bone = new SkeletonBone(); - skeleton_bone.name = x.name; - Transform transform = x.transform; - skeleton_bone.position = transform.localPosition; - skeleton_bone.rotation = transform.localRotation; - skeleton_bone.scale = transform.localScale; - return skeleton_bone; - }).ToArray(); + IEnumerable bones_enumerator = bones_; + + //Hipsボーンの親ボーン迄SkeletonBoneに入れる必要が有るので、確認と追加 + string hips_bone_name = ((HasBone("腰"))? "腰": "センター"); + Transform hips_parent_bone = bones_.Where(x=>x.name == hips_bone_name).Select(x=>x.transform.parent).FirstOrDefault(); + if (null != hips_parent_bone) { + //Hipsボーンの親ボーンが有るなら + //Hipsボーンの親ボーンがbones_に含まれているか確認する + if (!HasBone(hips_parent_bone.name)) { + //Hipsボーンの親ボーンがbones_に無いなら + //追加(Hipsボーン依りも前に追加しないといけないので注意) + bones_enumerator = Enumerable.Repeat(hips_parent_bone.gameObject, 1) + .Concat(bones_enumerator); + } + } + + var result = bones_enumerator.Select(x=>{ + SkeletonBone skeleton_bone = new SkeletonBone(); + skeleton_bone.name = x.name; + Transform transform = x.transform; + skeleton_bone.position = transform.localPosition; + skeleton_bone.rotation = transform.localRotation; + skeleton_bone.scale = transform.localScale; + return skeleton_bone; + }); + return result.ToArray(); } /// From c368f7c449bd50c21845c14048b57a29134dc3d9 Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 24 Dec 2013 00:10:29 +0900 Subject: [PATCH 35/37] =?UTF-8?q?MMDConverter:PMDConverter=E3=81=A8VMDConv?= =?UTF-8?q?erter=E3=81=AB=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/MMDLoader/PMDLoaderWindow.cs | 3 +- Editor/MMDLoader/Private/MMDConverter.cs | 1558 ---------------------- Editor/MMDLoader/Private/ModelAgent.cs | 4 +- Editor/MMDLoader/Private/MotionAgent.cs | 7 +- Editor/MMDLoader/Private/PMDConverter.cs | 1017 ++++++++++++++ Editor/MMDLoader/Private/VMDConverter.cs | 540 ++++++++ 6 files changed, 1563 insertions(+), 1566 deletions(-) delete mode 100644 Editor/MMDLoader/Private/MMDConverter.cs create mode 100644 Editor/MMDLoader/Private/PMDConverter.cs create mode 100644 Editor/MMDLoader/Private/VMDConverter.cs diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index 0ffab95..35862a9 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -1,13 +1,12 @@ using UnityEngine; using System.Collections; using UnityEditor; -using MMD.PMD; public class PMDLoaderWindow : EditorWindow { Object pmdFile = null; bool rigidFlag = true; bool use_mecanim = false; - PMDConverter.ShaderType shader_type = PMDConverter.ShaderType.MMDShader; + MMD.PMDConverter.ShaderType shader_type = MMD.PMDConverter.ShaderType.MMDShader; bool use_ik = true; float scale = 0.085f; diff --git a/Editor/MMDLoader/Private/MMDConverter.cs b/Editor/MMDLoader/Private/MMDConverter.cs deleted file mode 100644 index 78cd7bd..0000000 --- a/Editor/MMDLoader/Private/MMDConverter.cs +++ /dev/null @@ -1,1558 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System; -using System.IO; -using System.Linq; - -namespace MMD -{ - namespace PMD - { - public class PMDConverter - { - /// - /// シェーダの種類 - /// - public enum ShaderType - { - Default, /// Unityのデフォルトシェーダ - HalfLambert, /// もやっとしたLambertっぽくなる - MMDShader /// MMDっぽいシェーダ - } - - /// - /// GameObjectを作成する - /// - /// 内部形式データ - /// シェーダーの種類 - /// 剛体を使用するか - /// Mecanimを使用するか - /// IKを使用するか - /// スケール - public static GameObject CreateGameObject(PMDFormat format, ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { - PMDConverter converter = new PMDConverter(); - return converter.CreateGameObject_(format, shader_type, use_rigidbody, use_mecanim, use_ik, scale); - } - - /// - /// デフォルトコンストラクタ - /// - /// - /// ユーザーに依るインスタンス作成を禁止する - /// - private PMDConverter() {} - - private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { - format_ = format; - shader_type_ = shader_type; - use_rigidbody_ = use_rigidbody; - use_mecanim_ = use_mecanim; - use_ik_ = use_ik; - scale_ = scale; - root_game_object_ = new GameObject(format_.name); - - Mesh mesh = CreateMesh(); // メッシュの生成・設定 - Material[] materials = CreateMaterials(); // マテリアルの生成・設定 - GameObject[] bones = CreateBones(); // ボーンの生成・設定 - - // バインドポーズの作成 - BuildingBindpose(mesh, materials, bones); - - MMDEngine engine = root_game_object_.AddComponent(); - //スケール・エッジ幅 - engine.scale = scale_; - engine.outline_width = default_outline_width; - engine.material_outline_widths = Enumerable.Repeat(1.0f, materials.Length).ToArray(); - - // IKの登録 - if (use_ik_) - engine.ik_list = EntryIKSolver(bones); - - // 剛体関連 - if (use_rigidbody_) - { - try - { - var rigids = CreateRigids(bones); - AssignRigidbodyToBone(bones, rigids); - SetRigidsSettings(bones, rigids); - GameObject[] joints = SettingJointComponent(bones, rigids); - GlobalizeRigidbody(joints); - - // 非衝突グループ - List[] ignoreGroups = SettingIgnoreRigidGroups(rigids); - int[] groupTarget = GetRigidbodyGroupTargets(rigids); - - MMDEngine.Initialize(engine, groupTarget, ignoreGroups, rigids); - } - catch { } - } - - // Mecanim設定 - if (use_mecanim_) { - AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); - avatar_setting.SettingAvatar(); - - string path = format_.folder + "/"; - string name = GetFilePathString(format_.name); - string file_name = path + name + ".avatar.asset"; - avatar_setting.CreateAsset(file_name); - } else { - root_game_object_.AddComponent(); // アニメーション追加 - } - - return root_game_object_; - } - - Vector3[] EntryVertices() - { - int vcount = (int)format_.vertex_list.vert_count; - Vector3[] vpos = new Vector3[vcount]; - for (int i = 0; i < vcount; i++) - vpos[i] = format_.vertex_list.vertex[i].pos * scale_; - return vpos; - } - - Vector3[] EntryNormals() - { - int vcount = (int)format_.vertex_list.vert_count; - Vector3[] normals = new Vector3[vcount]; - for (int i = 0; i < vcount; i++) - normals[i] = format_.vertex_list.vertex[i].normal_vec; - return normals; - } - - Vector2[] EntryUVs() - { - int vcount = (int)format_.vertex_list.vert_count; - Vector2[] uvs = new Vector2[vcount]; - for (int i = 0; i < vcount; i++) - uvs[i] = format_.vertex_list.vertex[i].uv; - return uvs; - } - - BoneWeight[] EntryBoneWeights() - { - int vcount = (int)format_.vertex_list.vert_count; - BoneWeight[] weights = new BoneWeight[vcount]; - for (int i = 0; i < vcount; i++) - { - weights[i].boneIndex0 = (int)format_.vertex_list.vertex[i].bone_num[0]; - weights[i].boneIndex1 = (int)format_.vertex_list.vertex[i].bone_num[1]; - weights[i].weight0 = (float)format_.vertex_list.vertex[i].bone_weight / 100.0f; - weights[i].weight1 = 1.0f - weights[i].weight0; - } - return weights; - } - - // 頂点座標やUVなどの登録だけ - void EntryAttributesForMesh(Mesh mesh) - { - //mesh.vertexCount = (int)format_.vertex_list.vert_count; - mesh.vertices = EntryVertices(); - mesh.normals = EntryNormals(); - mesh.uv = EntryUVs(); - mesh.boneWeights = EntryBoneWeights(); - } - - void SetSubMesh(Mesh mesh) - { - // マテリアル対サブメッシュ - // サブメッシュとはマテリアルに適用したい面頂点データのこと - // 面ごとに設定するマテリアルはここ - mesh.subMeshCount = (int)format_.material_list.material_count; - - int sum = 0; - for (int i = 0; i < mesh.subMeshCount; i++) - { - int count = (int)format_.material_list.material[i].face_vert_count; - int[] indices = new int[count]; - - // 面頂点は材質0から順番に加算されている - for (int j = 0; j < count; j++) - indices[j] = format_.face_vertex_list.face_vert_index[j+sum]; - mesh.SetTriangles(indices, i); - sum += (int)format_.material_list.material[i].face_vert_count; - } - } - - // メッシュをProjectに登録 - void CreateAssetForMesh(Mesh mesh) - { - AssetDatabase.CreateAsset(mesh, format_.folder + "/" + format_.name + ".asset"); - } - - Mesh CreateMesh() - { - Mesh mesh = new Mesh(); - EntryAttributesForMesh(mesh); - SetSubMesh(mesh); - CreateAssetForMesh(mesh); - return mesh; - } - - //透過マテリアル確認(true:透過, false:不透明) - bool IsTransparentMaterial(PMD.PMDFormat.Material model_material, Texture2D texture) { - bool result = false; - result = result || (model_material.alpha < 0.98f); //0.98f以上は不透明と見做す(0.98fに影生成情報を埋め込んでいる為) - if (null != texture) { - result = result || texture.alphaIsTransparency; - } - return result; - } - - //エッジマテリアル確認(true:エッジ有り, false:無エッジ) - bool IsEdgeMaterial(PMD.PMDFormat.Material model_material) { - bool result; - if (0 == model_material.edge_flag) { - //エッジ無し - result = false; - } else { - //エッジ有りなら - result = true; - } - return result; - } - - //背面カリングマテリアル確認(true:背面カリングする, false:背面カリングしない) - bool IsCullBackMaterial(PMD.PMDFormat.Material model_material) { - bool result; - if (1.0f <= model_material.alpha) { - //不透明なら - //背面カリングする - result = true; - } else if (0.99f <= model_material.alpha) { - //不透明の両面描画なら - //背面カリングしない - result = false; - } else { - //透過なら - //背面カリングしない - result = false; - } - return result; - } - - //無影マテリアル確認(true:無影, false:影放ち) - bool IsNoCastShadowMaterial(PMD.PMDFormat.Material model_material) { - bool result; - if (0 == model_material.edge_flag) { - //エッジ無し - //無影 - result = true; - } else { - //エッジ有りなら - //影放ち - result = false; - } - return result; - } - - //影受け無しマテリアル確認(true:影受け無し, false:影受け) - bool IsNoReceiveShadowMaterial(PMD.PMDFormat.Material model_material) { - bool result; - if (0.98f == model_material.alpha) { //浮動小数点の比較だけど、0.98fとの同値確認でPMXエディタの0.98と一致したので一旦これで。 - //影受け無し(不透明度が0.98fは特別扱いで影受け無し)なら - result = true; - } else { - //影受け有りなら - result = false; - } - return result; - } - - string GetMMDShaderPath(PMD.PMDFormat.Material model_material, Texture2D texture) { - string result = "MMD/"; - if (IsTransparentMaterial(model_material, texture)) { - result += "Transparent/"; - } - result += "PMDMaterial"; - if (IsEdgeMaterial(model_material)) { - result += "-with-Outline"; - } - if (IsCullBackMaterial(model_material)) { - result += "-CullBack"; - } - if (IsNoCastShadowMaterial(model_material)) { - result += "-NoCastShadow"; - } -#if MFU_ENABLE_NO_RECEIVE_SHADOW_SHADER //影受け無しのシェーダはまだ無いので無効化 - if (IsNoReceiveShadowMaterial(model_material)) { - result += "-NoReceiveShadow"; - } -#endif //MFU_ENABLE_NO_RECEIVE_SHADOW_SHADER - return result; - } - - // 色の生成 - void EntryColors(Material[] mats) - { - // マテリアルの生成 - for (int i = 0; i < mats.Length; i++) - { - // PMDフォーマットのマテリアルを取得 - PMD.PMDFormat.Material pmdMat = format_.material_list.material[i]; - - //先にテクスチャ情報を検索 - Texture2D main_texture = null; - if (pmdMat.texture_file_name != "") { - string path = format_.folder + "/" + pmdMat.texture_file_name; - main_texture = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D; - } - - //マテリアルに設定 - switch (shader_type_) - { - case ShaderType.Default: // デフォルト - mats[i] = new Material(Shader.Find("Transparent/Diffuse")); - mats[i].color = pmdMat.diffuse_color; - Color cbuf = mats[i].color; - cbuf.a = pmdMat.alpha; // これでいいのか? - mats[i].color = cbuf; - break; - - case ShaderType.HalfLambert: // ハーフランバート - mats[i] = new Material(Shader.Find("Custom/CharModel")); - mats[i].SetFloat("_Cutoff", 1 - pmdMat.alpha); - mats[i].color = pmdMat.diffuse_color; - break; - - case ShaderType.MMDShader: - mats[i] = new Material(Shader.Find(GetMMDShaderPath(pmdMat, main_texture))); - - // シェーダに依って値が有ったり無かったりするが、設定してもエラーに為らない様なので全部設定 - mats[i].SetColor("_Color", pmdMat.diffuse_color); - mats[i].SetColor("_AmbColor", pmdMat.mirror_color); - mats[i].SetFloat("_Opacity", pmdMat.alpha); - mats[i].SetColor("_SpecularColor", pmdMat.specular_color); - mats[i].SetFloat("_Shininess", pmdMat.specularity); - // エッジ - const float c_default_scale = 0.085f; //0.085fの時にMMDと一致する様にしているので、それ以外なら補正 - mats[i].SetFloat("_OutlineWidth", default_outline_width * scale_ / c_default_scale); - mats[i].SetColor("_OutlineColor", default_outline_color); - - // ここでスフィアマップ - string path = format_.folder + "/" + pmdMat.sphere_map_name; - Texture sphere_map; - - if (File.Exists(path)) - { // ファイルの存在を確認 - sphere_map = UnityEditor.AssetDatabase.LoadAssetAtPath(path, typeof(Texture)) as Texture; - - // 乗算と加算判定 - string ext = Path.GetExtension(pmdMat.sphere_map_name); - switch (ext) { - case ".spa": // 加算 - mats[i].SetTexture("_SphereAddTex", sphere_map); - mats[i].SetTextureScale("_SphereAddTex", new Vector2(1, -1)); - break; - case ".sph": // 乗算 - mats[i].SetTexture("_SphereMulTex", sphere_map); - mats[i].SetTextureScale("_SphereMulTex", new Vector2(1, -1)); - break; - default: - // 加算扱い - goto case ".spa"; - } - } - - // トゥーンの位置を取得 - string toon_name = pmdMat.toon_index != 0xFF ? - format_.toon_texture_list.toon_texture_file[pmdMat.toon_index] : "toon00.bmp"; - string resource_path = UnityEditor.AssetDatabase.GetAssetPath(Shader.Find("MMD/HalfLambertOutline")); - resource_path = Path.GetDirectoryName(resource_path); // resourceディレクトリを取得 - resource_path += "/toon/" + toon_name; - - // トゥーンが存在するか確認 - if (!File.Exists(resource_path)) - { - // 自前トゥーンの可能性がある - resource_path = format_.folder + "/" + format_.toon_texture_list.toon_texture_file[pmdMat.toon_index]; - if (!File.Exists(resource_path)) - { - Debug.LogError("Do not exists toon texture: " + format_.toon_texture_list.toon_texture_file[pmdMat.toon_index]); - break; - } - } - - // テクスチャの割り当て - Texture toon_tex = UnityEditor.AssetDatabase.LoadAssetAtPath(resource_path, typeof(Texture)) as Texture; - mats[i].SetTexture("_ToonTex", toon_tex); - mats[i].SetTextureScale("_ToonTex", new Vector2(1, -1)); - break; - } - - // テクスチャが空でなければ登録 - if (null != main_texture) { - mats[i].mainTexture = main_texture; - mats[i].mainTextureScale = new Vector2(1, -1); - } - } - } - - // マテリアルに必要な色などを登録 - Material[] EntryAttributesForMaterials() - { - int count = (int)format_.material_list.material_count; - Material[] mats = new Material[count]; - EntryColors(mats); - return mats; - } - - // マテリアルの登録 - void CreateAssetForMaterials(Material[] mats) - { - // 適当なフォルダに投げる - string path = format_.folder + "/Materials/"; - if (!System.IO.Directory.Exists(path)) { - AssetDatabase.CreateFolder(format_.folder, "Materials"); - } - - for (int i = 0; i < mats.Length; i++) - { - string fname = path + format_.name + "_material" + i + ".asset"; - AssetDatabase.CreateAsset(mats[i], fname); - } - } - - // マテリアルの生成 - Material[] CreateMaterials() - { - Material[] materials; - materials = EntryAttributesForMaterials(); - CreateAssetForMaterials(materials); - return materials; - } - - // 親子関係の構築 - void AttachParentsForBone(GameObject[] bones) - { - for (int i = 0; i < bones.Length; i++) - { - int index = format_.bone_list.bone[i].parent_bone_index; - if (index != 0xFFFF) - bones[i].transform.parent = bones[index].transform; - else - bones[i].transform.parent = root_game_object_.transform; - } - } - - // ボーンの位置決めや親子関係の整備など - GameObject[] EntryAttributeForBones() - { - int count = format_.bone_list.bone_count; - GameObject[] bones = new GameObject[count]; - - for (int i = 0; i < count; i++) { - bones[i] = new GameObject(format_.bone_list.bone[i].bone_name); - bones[i].transform.name = bones[i].name; - bones[i].transform.position = format_.bone_list.bone[i].bone_head_pos * scale_; - } - return bones; - } - - // ボーンの生成 - GameObject[] CreateBones() - { - GameObject[] bones; - bones = EntryAttributeForBones(); - AttachParentsForBone(bones); - CreateSkinBone(bones); - return bones; - } - - // 表情ボーンの生成を行う - void CreateSkinBone(GameObject[] bones) - { - // 表情ルートを生成してルートの子供に付ける - GameObject skin_root = new GameObject("Expression"); - if (skin_root.GetComponent() == null) - skin_root.AddComponent(); - skin_root.transform.parent = root_game_object_.transform; - - for (int i = 0; i < format_.skin_list.skin_count; i++) - { - // 表情を親ボーンに付ける - GameObject skin = new GameObject(format_.skin_list.skin_data[i].skin_name); - skin.transform.parent = skin_root.transform; - var script = skin.AddComponent(); - - // モーフの情報を入れる - AssignMorphVectorsForSkin(format_.skin_list.skin_data[i], format_.vertex_list, script); - } - } - - // モーフ情報(頂点インデックス、モーフ先頂点など)を記録する - void AssignMorphVectorsForSkin(PMD.PMDFormat.SkinData data, PMD.PMDFormat.VertexList vtxs, MMDSkinsScript script) - { - uint count = data.skin_vert_count; - int[] indices = new int[count]; - Vector3[] morph_target = new Vector3[count]; - - for (int i = 0; i < count; i++) - { - // ここで設定する - indices[i] = (int)data.skin_vert_data[i].skin_vert_index; - - // モーフ先 - 元頂点 - //morph_target[i] = (data.skin_vert_data[i].skin_vert_pos - vtxs.vertex[indices[i]].pos).normalized; - //morph_target[i] = data.skin_vert_data[i].skin_vert_pos - vtxs.vertex[indices[i]].pos; - morph_target[i] = data.skin_vert_data[i].skin_vert_pos * scale_; - } - - // スクリプトに記憶させる - script.morphTarget = morph_target; - script.targetIndices = indices; - - switch (data.skin_type) - { - case 0: - script.skinType = MMDSkinsScript.SkinType.Base; - script.gameObject.name = "base"; - break; - - case 1: - script.skinType = MMDSkinsScript.SkinType.EyeBrow; - break; - - case 2: - script.skinType = MMDSkinsScript.SkinType.Eye; - break; - - case 3: - script.skinType = MMDSkinsScript.SkinType.Lip; - break; - - case 4: - script.skinType = MMDSkinsScript.SkinType.Other; - break; - } - } - - // バインドポーズの作成 - void BuildingBindpose(Mesh mesh, Material[] materials, GameObject[] bones) - { - // 行列とかトランスフォームとか - Matrix4x4[] bindpose = new Matrix4x4[bones.Length]; - Transform[] trans = new Transform[bones.Length]; - for (int i = 0; i < bones.Length; i++) { - trans[i] = bones[i].transform; - bindpose[i] = bones[i].transform.worldToLocalMatrix; - } - - // ここで本格的な適用 - SkinnedMeshRenderer smr = root_game_object_.AddComponent() as SkinnedMeshRenderer; - mesh.bindposes = bindpose; - smr.sharedMesh = mesh; - smr.bones = trans; - smr.materials = materials; - smr.receiveShadows = false; //影を受けない - ExpressionManagerScript ems = root_game_object_.GetComponentInChildren(); - ems.mesh = mesh; - } - - // IKの登録 - // IKは基本的にスクリプトを利用 - CCDIKSolver[] EntryIKSolver(GameObject[] bones) - { - PMD.PMDFormat.IKList ik_list = format_.ik_list; - - CCDIKSolver[] iksolvers = new CCDIKSolver[ik_list.ik_data_count]; - for (int i = 0; i < ik_list.ik_data_count; i++) - { - PMD.PMDFormat.IK ik = ik_list.ik_data[i]; - - bones[ik.ik_bone_index].AddComponent(); - CCDIKSolver solver = bones[ik.ik_bone_index].GetComponent(); - solver.target = bones[ik.ik_target_bone_index].transform; - solver.controll_weight = ik.control_weight * 4; // PMDファイルは4倍らしい - solver.iterations = ik.iterations; - solver.chains = new Transform[ik.ik_chain_length]; - for (int j = 0; j < ik.ik_chain_length; j++) - solver.chains[j] = bones[ik.ik_child_bone_index[j]].transform; - - if (!(bones[ik.ik_bone_index].name.Contains("足") || bones[ik.ik_bone_index].name.Contains("つま先"))) - { - solver.enabled = false; - } - iksolvers[i] = solver; - } - - return iksolvers; - } - - // Sphere Colliderの設定 - Collider EntrySphereCollider(PMDFormat.Rigidbody rigid, GameObject obj) - { - SphereCollider collider = obj.AddComponent(); - collider.radius = rigid.shape_w * scale_; - return collider; - } - - // Box Colliderの設定 - Collider EntryBoxCollider(PMDFormat.Rigidbody rigid, GameObject obj) - { - BoxCollider collider = obj.AddComponent(); - collider.size = new Vector3( - rigid.shape_w * 2f * scale_, - rigid.shape_h * 2f * scale_, - rigid.shape_d * 2f * scale_); - return collider; - } - - // Capsule Colliderの設定 - Collider EntryCapsuleCollider(PMDFormat.Rigidbody rigid, GameObject obj) - { - CapsuleCollider collider = obj.AddComponent(); - collider.radius = rigid.shape_w * scale_; - collider.height = (rigid.shape_h + rigid.shape_w * 2) * scale_; - return collider; - } - - // 物理素材の定義 - PhysicMaterial CreatePhysicMaterial(PMDFormat.Rigidbody rigid) - { - PhysicMaterial material = new PhysicMaterial(format_.name + "_r" + rigid.rigidbody_name); - material.bounciness = rigid.rigidbody_recoil; - material.staticFriction = rigid.rigidbody_friction; - material.dynamicFriction = rigid.rigidbody_friction; - - AssetDatabase.CreateAsset(material, format_.folder + "/Physics/" + GetFilePathString(material.name) + ".asset"); - return material; - } - - // Unity側のRigidbodyの設定を行う - void UnityRigidbodySetting(PMDFormat.Rigidbody rigidbody, GameObject targetBone, bool setted=false) - { - // rigidbodyの調整 - if (!setted) - { - targetBone.rigidbody.isKinematic = (0 == rigidbody.rigidbody_type); - targetBone.rigidbody.mass = Mathf.Max(float.Epsilon, rigidbody.rigidbody_weight); - targetBone.rigidbody.drag = rigidbody.rigidbody_pos_dim; - targetBone.rigidbody.angularDrag = rigidbody.rigidbody_rot_dim; - } - else - { - // Rigidbodyはボーンに対して適用されるので複数ある場合は平均を取る - targetBone.rigidbody.mass += rigidbody.rigidbody_weight; - targetBone.rigidbody.drag += rigidbody.rigidbody_pos_dim; - targetBone.rigidbody.angularDrag += rigidbody.rigidbody_rot_dim; - targetBone.rigidbody.mass *= 0.5f; - targetBone.rigidbody.drag *= 0.5f; - targetBone.rigidbody.angularDrag *= 0.5f; - } - } - - // 剛体の値を代入する - void SetRigidsSettings(GameObject[] bones, GameObject[] rigid) - { - PMDFormat.RigidbodyList list = format_.rigidbody_list; - for (int i = 0; i < list.rigidbody_count; i++) // iは剛体番号 - { - // 剛体の関連ボーンのインデックス - int rigidRefIndex = list.rigidbody[i].rigidbody_rel_bone_index; - - // ローカル座標の確定 - Vector3 localPos = list.rigidbody[i].pos_pos * scale_;// - rigid[i].transform.position; - - // ここで位置の決定 - if (rigidRefIndex >= ushort.MaxValue) - { - // 関連ボーン無し - if (rigid[i].rigidbody == null) - rigid[i].AddComponent(); - UnityRigidbodySetting(list.rigidbody[i], rigid[i]); - rigid[i].transform.localPosition = localPos; - - // 関連ボーンなしの剛体はセンターボーンに接続している - rigid[i].transform.position = localPos + format_.bone_list.bone[0].bone_head_pos * scale_; - // 回転の値を決める - Vector3 rot = list.rigidbody[i].pos_rot * Mathf.Rad2Deg; - rigid[i].transform.rotation = Quaternion.Euler(rot); - } - else - // 関連ボーン有り - { // とりあえずここで剛体を追加・設定 - if (bones[rigidRefIndex].rigidbody == null) - bones[rigidRefIndex].AddComponent(); - UnityRigidbodySetting(list.rigidbody[i], bones[rigidRefIndex]); - rigid[i].transform.localPosition = localPos; - // 回転の値を決める - Vector3 rot = list.rigidbody[i].pos_rot * Mathf.Rad2Deg; - rigid[i].transform.rotation = Quaternion.Euler(rot); - } - - } - } - - // 剛体の生成 - GameObject[] CreateRigids(GameObject[] bones) - { - PMDFormat.RigidbodyList list = format_.rigidbody_list; - if (!System.IO.Directory.Exists(System.IO.Path.Combine(format_.folder, "Physics"))) - { - AssetDatabase.CreateFolder(format_.folder, "Physics"); - } - - // 剛体の登録 - GameObject[] rigid = new GameObject[list.rigidbody_count]; - for (int i = 0; i < list.rigidbody_count; i++) - { - rigid[i] = new GameObject("r" + list.rigidbody[i].rigidbody_name); - //rigid[i].AddComponent(); // 剛体本体にはrigidbodyは適用しない - - // 各種Colliderの設定 - Collider collider = null; - switch (list.rigidbody[i].shape_type) - { - case 0: - collider = EntrySphereCollider(list.rigidbody[i], rigid[i]); - break; - - case 1: - collider = EntryBoxCollider(list.rigidbody[i], rigid[i]); - break; - - case 2: - collider = EntryCapsuleCollider(list.rigidbody[i], rigid[i]); - break; - } - - // マテリアルの設定 - collider.material = CreatePhysicMaterial(list.rigidbody[i]); - } - return rigid; - } - - // ジョインに依って接続している(されている)剛体番号を検索する - int SearchConnectRigidByJoint(int rigidIndex) - { - for (int i = 0; i < format_.rigidbody_joint_list.joint_count; i++) - { - int joint_rigidbody_a = (int)format_.rigidbody_joint_list.joint[i].joint_rigidbody_a; - int joint_rigidbody_b = (int)format_.rigidbody_joint_list.joint[i].joint_rigidbody_b; - if (joint_rigidbody_b == rigidIndex) - { - return joint_rigidbody_a; - } - else if (joint_rigidbody_a == rigidIndex) - { - return joint_rigidbody_b; - } - } - // 接続剛体は発見出来ず - return -1; - } - - // 関連ボーンなしの剛体から親のボーンを探してくる - // rigidIndexは剛体番号 - int GetTargetRigidBone(int rigidIndex) - { - // 接続剛体Aを探す - int targetRigid = SearchConnectRigidByJoint(rigidIndex); - - // 接続剛体Aの関連ボーンを探す - int ind = format_.rigidbody_list.rigidbody[targetRigid].rigidbody_rel_bone_index; - - // MaxValueを引けば接続剛体Aの関連ボーンに接続されるようになっている - if (ind >= ushort.MaxValue) - format_.rigidbody_list.rigidbody[rigidIndex].rigidbody_rel_bone_index = ushort.MaxValue + (ushort)ind; - - return (int)ind; - } - - // 剛体ボーンを - void AssignRigidbodyToBone(GameObject[] bones, GameObject[] rigids) - { - // 剛体の数だけ回す - for (int i = 0; i < rigids.Length; i++) - { - // 剛体を親ボーンに格納 - int refIndex = format_.rigidbody_list.rigidbody[i].rigidbody_rel_bone_index; - if (refIndex != ushort.MaxValue) - { // 65535が最大値 - rigids[i].transform.parent = bones[refIndex].transform; - } - else - { - // ジョイントから接続剛体B=現在の剛体名で探し出す - int boneIndex = GetTargetRigidBone(i); - - // 接続剛体Aの関連ボーンに剛体を接続 - rigids[i].transform.parent = bones[boneIndex].transform; - } - } - } - - // 移動や回転制限 - void SetMotionAngularLock(PMDFormat.Joint joint, ConfigurableJoint conf) - { - SoftJointLimit jlim; - - // Motionの固定 - if (joint.constrain_pos_1.x == 0f && joint.constrain_pos_2.x == 0f) - conf.xMotion = ConfigurableJointMotion.Locked; - else - conf.xMotion = ConfigurableJointMotion.Limited; - - if (joint.constrain_pos_1.y == 0f && joint.constrain_pos_2.y == 0f) - conf.yMotion = ConfigurableJointMotion.Locked; - else - conf.yMotion = ConfigurableJointMotion.Limited; - - if (joint.constrain_pos_1.z == 0f && joint.constrain_pos_2.z == 0f) - conf.zMotion = ConfigurableJointMotion.Locked; - else - conf.zMotion = ConfigurableJointMotion.Limited; - - // 角度の固定 - if (joint.constrain_rot_1.x == 0f && joint.constrain_rot_2.x == 0f) - conf.angularXMotion = ConfigurableJointMotion.Locked; - else - { - conf.angularXMotion = ConfigurableJointMotion.Limited; - float hlim = Mathf.Max(-joint.constrain_rot_1.x, -joint.constrain_rot_2.x); //回転方向が逆なので負数 - float llim = Mathf.Min(-joint.constrain_rot_1.x, -joint.constrain_rot_2.x); - SoftJointLimit jhlim = new SoftJointLimit(); - jhlim.limit = Mathf.Clamp(hlim * Mathf.Rad2Deg, -180.0f, 180.0f); - conf.highAngularXLimit = jhlim; - - SoftJointLimit jllim = new SoftJointLimit(); - jllim.limit = Mathf.Clamp(llim * Mathf.Rad2Deg, -180.0f, 180.0f); - conf.lowAngularXLimit = jllim; - } - - if (joint.constrain_rot_1.y == 0f && joint.constrain_rot_2.y == 0f) - conf.angularYMotion = ConfigurableJointMotion.Locked; - else - { - // 値がマイナスだとエラーが出るので注意 - conf.angularYMotion = ConfigurableJointMotion.Limited; - float lim = Mathf.Min(Mathf.Abs(joint.constrain_rot_1.y), Mathf.Abs(joint.constrain_rot_2.y));//絶対値の小さい方 - jlim = new SoftJointLimit(); - jlim.limit = lim * Mathf.Clamp(Mathf.Rad2Deg, 0.0f, 180.0f); - conf.angularYLimit = jlim; - } - - if (joint.constrain_rot_1.z == 0f && joint.constrain_rot_2.z == 0f) - conf.angularZMotion = ConfigurableJointMotion.Locked; - else - { - conf.angularZMotion = ConfigurableJointMotion.Limited; - float lim = Mathf.Min(Mathf.Abs(-joint.constrain_rot_1.z), Mathf.Abs(-joint.constrain_rot_2.z));//絶対値の小さい方//回転方向が逆なので負数 - jlim = new SoftJointLimit(); - jlim.limit = Mathf.Clamp(lim * Mathf.Rad2Deg, 0.0f, 180.0f); - conf.angularZLimit = jlim; - } - } - - // ばねの設定など - void SetDrive(PMDFormat.Joint joint, ConfigurableJoint conf) - { - JointDrive drive; - - // Position - if (joint.spring_pos.x != 0f) - { - drive = new JointDrive(); - drive.positionSpring = joint.spring_pos.x * scale_; - conf.xDrive = drive; - } - if (joint.spring_pos.y != 0f) - { - drive = new JointDrive(); - drive.positionSpring = joint.spring_pos.y * scale_; - conf.yDrive = drive; - } - if (joint.spring_pos.z != 0f) - { - drive = new JointDrive(); - drive.positionSpring = joint.spring_pos.z * scale_; - conf.zDrive = drive; - } - - // Angular - if (joint.spring_rot.x != 0f) - { - drive = new JointDrive(); - drive.mode = JointDriveMode.PositionAndVelocity; - drive.positionSpring = joint.spring_rot.x; - conf.angularXDrive = drive; - } - if (joint.spring_rot.y != 0f || joint.spring_rot.z != 0f) - { - drive = new JointDrive(); - drive.mode = JointDriveMode.PositionAndVelocity; - drive.positionSpring = (joint.spring_rot.y + joint.spring_rot.z) * 0.5f; - conf.angularYZDrive = drive; - } - } - - // ConfigurableJointの値を設定する - void SetAttributeConfigurableJoint(PMDFormat.Joint joint, ConfigurableJoint conf) - { - SetMotionAngularLock(joint, conf); - SetDrive(joint, conf); - } - - // ConfigurableJointの設定 - // 先に設定してからFixedJointを設定する - GameObject[] SetupConfigurableJoint(GameObject[] rigids) - { - List result_list = new List(); - foreach (PMDFormat.Joint joint in format_.rigidbody_joint_list.joint) { - //相互接続する剛体の取得 - Transform transform_a = rigids[joint.joint_rigidbody_a].transform; - Transform transform_b = rigids[joint.joint_rigidbody_b].transform; - Rigidbody rigidbody_a = transform_a.rigidbody; - if (null == rigidbody_a) { - rigidbody_a = transform_a.parent.rigidbody; - } - Rigidbody rigidbody_b = transform_b.rigidbody; - if (null == rigidbody_b) { - rigidbody_b = transform_b.parent.rigidbody; - } - if (rigidbody_a != rigidbody_b) { - //接続する剛体が同じ剛体を指さないなら - //(本来ならPMDの設定が間違っていない限り同一を指す事は無いが、MFUでは関連ボーンを持たない剛体はセンターボーンに纏められる為に依り起こり得る) - //ジョイント設定 - ConfigurableJoint config_joint = rigidbody_b.gameObject.AddComponent(); - config_joint.connectedBody = rigidbody_a; - SetAttributeConfigurableJoint(joint, config_joint); - - result_list.Add(config_joint.gameObject); - } - } - return result_list.ToArray(); - } - - // ジョイントの設定 - // ジョイントはボーンに対して適用される - GameObject[] SettingJointComponent(GameObject[] bones, GameObject[] rigids) - { - // ConfigurableJointの設定 - GameObject[] joints = SetupConfigurableJoint(rigids); - return joints; - } - - // 剛体のグローバル座標化 - void GlobalizeRigidbody(GameObject[] joints) - { - if ((null != joints) && (0 < joints.Length)) { - // 物理演算ルートを生成してルートの子供に付ける - GameObject physics_root = new GameObject("Physics"); - PhysicsManager physics_manager = physics_root.AddComponent(); - physics_root.transform.parent = root_game_object_.transform; - Transform physics_root_transform = physics_root.transform; - - // PhysicsManagerに移動前の状態を覚えさせる(幾つか重複しているので重複は削除) - physics_manager.connect_bone_list = joints.Select(x=>x.gameObject) - .Distinct() - .Select(x=>new PhysicsManager.ConnectBone(x, x.transform.parent.gameObject)) - .ToArray(); - - //isKinematicで無くConfigurableJointを持つ場合はグローバル座標化 - foreach (ConfigurableJoint joint in joints.Where(x=>!x.GetComponent().isKinematic) - .Select(x=>x.GetComponent())) { - joint.transform.parent = physics_root_transform; - } - } - } - - // 非衝突剛体の設定 - List[] SettingIgnoreRigidGroups(GameObject[] rigids) - { - // 非衝突グループ用リストの初期化 - const int MaxGroup = 16; // グループの最大数 - List[] ignoreRigid = new List[MaxGroup]; - for (int i = 0; i < 16; i++) ignoreRigid[i] = new List(); - - // それぞれの剛体が所属している非衝突グループを追加していく - PMDFormat.RigidbodyList list = format_.rigidbody_list; - for (int i = 0; i < list.rigidbody_count; i++) - ignoreRigid[list.rigidbody[i].rigidbody_group_index].Add(i); - return ignoreRigid; - } - - // グループターゲット - int[] GetRigidbodyGroupTargets(GameObject[] rigids) - { - int[] result = new int[rigids.Length]; - for (int i = 0; i < rigids.Length; i++) - { - result[i] = format_.rigidbody_list.rigidbody[i].rigidbody_group_target; - } - return result; - } - - /// - /// ファイルパス文字列の取得 - /// - /// ファイルパスに使用可能な文字列 - /// ファイルパスに使用したい文字列 - private static string GetFilePathString(string src) { - return src.Replace('\\', '\') - .Replace('/', '/') - .Replace(':', ':') - .Replace('*', '*') - .Replace('?', '?') - .Replace('"', '”') - .Replace('<', '<') - .Replace('>', '>') - .Replace('|', '|') - .Replace("\n", string.Empty) - .Replace("\r", string.Empty); - } - - static float default_outline_width = 0.2f; //標準エッジ幅 - static Color default_outline_color = Color.black; //標準エッジ色 - - GameObject root_game_object_; - PMDFormat format_; - ShaderType shader_type_; - bool use_rigidbody_; - bool use_mecanim_; - bool use_ik_; - float scale_; - } - } - - namespace VMD - { - public class VMDConverter - { - /// - /// AnimationClipを作成する - /// - /// 内部形式データ - /// 使用するPMDのGameObject - /// 補完曲線品質 - public static AnimationClip CreateAnimationClip(VMDFormat format, GameObject assign_pmd, int interpolationQuality) { - VMDConverter converter = new VMDConverter(); - return converter.CreateAnimationClip_(format, assign_pmd, interpolationQuality); - } - - /// - /// デフォルトコンストラクタ - /// - /// - /// ユーザーに依るインスタンス作成を禁止する - /// - private VMDConverter() {} - - // クリップをアニメーションに登録する - private AnimationClip CreateAnimationClip_(MMD.VMD.VMDFormat format, GameObject assign_pmd, int interpolationQuality) - { - //スケール設定 - scale_ = 1.0f; - if (assign_pmd) { - MMDEngine engine = assign_pmd.GetComponent(); - if (engine) { - scale_ = engine.scale; - } - } - - //Animation anim = assign_pmd.GetComponent(); - - // クリップの作成 - AnimationClip clip = new AnimationClip(); - clip.name = assign_pmd.name + "_" + format.name; - - Dictionary bone_path = new Dictionary(); - Dictionary gameobj = new Dictionary(); - GetGameObjects(gameobj, assign_pmd); // 親ボーン下のGameObjectを取得 - FullSearchBonePath(assign_pmd.transform, bone_path); - FullEntryBoneAnimation(format, clip, bone_path, gameobj, interpolationQuality); - - CreateKeysForSkin(format, clip); // 表情の追加 - - return clip; - } - - // ベジェハンドルを取得する - // 0~127の値を 0f~1fとして返す - static Vector2 GetBezierHandle(byte[] interpolation, int type, int ab) - { - // 0=X, 1=Y, 2=Z, 3=R - // abはa?かb?のどちらを使いたいか - Vector2 bezierHandle = new Vector2((float)interpolation[ab*8+type], (float)interpolation[ab*8+4+type]); - return bezierHandle/127f; - } - // p0:(0f,0f),p3:(1f,1f)のベジェ曲線上の点を取得する - // tは0~1の範囲 - static Vector2 SampleBezier(Vector2 bezierHandleA, Vector2 bezierHandleB, float t) - { - Vector2 p0 = Vector2.zero; - Vector2 p1 = bezierHandleA; - Vector2 p2 = bezierHandleB; - Vector2 p3 = new Vector2(1f,1f); - - Vector2 q0 = Vector2.Lerp(p0, p1, t); - Vector2 q1 = Vector2.Lerp(p1, p2, t); - Vector2 q2 = Vector2.Lerp(p2, p3, t); - - Vector2 r0 = Vector2.Lerp(q0, q1, t); - Vector2 r1 = Vector2.Lerp(q1, q2, t); - - Vector2 s0 = Vector2.Lerp(r0, r1, t); - return s0; - } - // 補間曲線が線形補間と等価か - static bool IsLinear(byte[] interpolation, int type) - { - byte ax=interpolation[0*8+type]; - byte ay=interpolation[0*8+4+type]; - byte bx=interpolation[1*8+type]; - byte by=interpolation[1*8+4+type]; - return (ax == ay) && (bx == by); - } - // 補間曲線の近似のために追加するキーフレームを含めたキーフレーム数を取得する - int GetKeyframeCount(List mlist, int type, int interpolationQuality) - { - int count = 0; - for(int i = 0; i < mlist.Count; i++) - { - if(i>0 && !IsLinear(mlist[i].interpolation, type)) - { - count += interpolationQuality;//Interpolation Keyframes - } - else - { - count += 1;//Keyframe - } - } - return count; - } - //キーフレームが1つの時、ダミーキーフレームを追加する - void AddDummyKeyframe(ref Keyframe[] keyframes) - { - if(keyframes.Length==1) - { - Keyframe[] newKeyframes=new Keyframe[2]; - newKeyframes[0]=keyframes[0]; - newKeyframes[1]=keyframes[0]; - newKeyframes[1].time+=0.001f/60f;//1[ms] - newKeyframes[0].outTangent=0f; - newKeyframes[1].inTangent=0f; - keyframes=newKeyframes; - } - } - // 任意の型のvalueを持つキーフレーム - abstract class CustomKeyframe - { - public CustomKeyframe(float time,Type value) - { - this.time=time; - this.value=value; - } - public float time{ get; set; } - public Type value{ get; set; } - } - // float型のvalueを持つキーフレーム - class FloatKeyframe:CustomKeyframe - { - public FloatKeyframe(float time,float value):base(time,value) - { - } - // 線形補間 - public static FloatKeyframe Lerp(FloatKeyframe from, FloatKeyframe to,Vector2 t) - { - return new FloatKeyframe( - Mathf.Lerp(from.time,to.time,t.x), - Mathf.Lerp(from.value,to.value,t.y) - ); - } - // ベジェを線形補間で近似したキーフレームを追加する - public static void AddBezierKeyframes(byte[] interpolation, int type, - FloatKeyframe prev_keyframe,FloatKeyframe cur_keyframe, int interpolationQuality, - ref FloatKeyframe[] keyframes,ref int index) - { - if(prev_keyframe==null || IsLinear(interpolation,type)) - { - keyframes[index++]=cur_keyframe; - } - else - { - Vector2 bezierHandleA=GetBezierHandle(interpolation,type,0); - Vector2 bezierHandleB=GetBezierHandle(interpolation,type,1); - int sampleCount = interpolationQuality; - for(int j = 0; j < sampleCount; j++) - { - float t = (j+1)/(float)sampleCount; - Vector2 sample = SampleBezier(bezierHandleA,bezierHandleB,t); - keyframes[index++] = FloatKeyframe.Lerp(prev_keyframe,cur_keyframe,sample); - } - } - } - } - // Quaternion型のvalueを持つキーフレーム - class QuaternionKeyframe:CustomKeyframe - { - public QuaternionKeyframe(float time,Quaternion value):base(time,value) - { - } - // 線形補間 - public static QuaternionKeyframe Lerp(QuaternionKeyframe from, QuaternionKeyframe to,Vector2 t) - { - return new QuaternionKeyframe( - Mathf.Lerp(from.time,to.time,t.x), - Quaternion.Slerp(from.value,to.value,t.y) - ); - } - // ベジェを線形補間で近似したキーフレームを追加する - public static void AddBezierKeyframes(byte[] interpolation, int type, - QuaternionKeyframe prev_keyframe,QuaternionKeyframe cur_keyframe, int interpolationQuality, - ref QuaternionKeyframe[] keyframes,ref int index) - { - if(prev_keyframe==null || IsLinear(interpolation,type)) - { - keyframes[index++]=cur_keyframe; - } - else - { - Vector2 bezierHandleA=GetBezierHandle(interpolation,type,0); - Vector2 bezierHandleB=GetBezierHandle(interpolation,type,1); - int sampleCount = interpolationQuality; - for(int j = 0; j < sampleCount; j++) - { - float t=(j+1)/(float)sampleCount; - Vector2 sample = SampleBezier(bezierHandleA,bezierHandleB,t); - keyframes[index++] = QuaternionKeyframe.Lerp(prev_keyframe,cur_keyframe,sample); - } - } - } - - } - - //移動の線形補間用tangentを求める - float GetLinearTangentForPosition(Keyframe from_keyframe,Keyframe to_keyframe) - { - return (to_keyframe.value-from_keyframe.value)/(to_keyframe.time-from_keyframe.time); - } - //-359~+359度の範囲を等価な0~359度へ変換する。 - float Mod360(float angle) - { - //剰余演算の代わりに加算にする - return (angle<0)?(angle+360f):(angle); - } - //回転の線形補間用tangentを求める - float GetLinearTangentForRotation(Keyframe from_keyframe,Keyframe to_keyframe) - { - float tv=Mod360(to_keyframe.value); - float fv=Mod360(from_keyframe.value); - float delta_value=Mod360(tv-fv); - //180度を越える場合は逆回転 - if(delta_value<180f) - { - return delta_value/(to_keyframe.time-from_keyframe.time); - } - else - { - return (delta_value-360f)/(to_keyframe.time-from_keyframe.time); - } - } - //アニメーションエディタでBothLinearを選択したときの値 - private const int TangentModeBothLinear=21; - - //UnityのKeyframeに変換する(回転用) - void ToKeyframesForRotation(QuaternionKeyframe[] custom_keys,ref Keyframe[] rx_keys,ref Keyframe[] ry_keys,ref Keyframe[] rz_keys) - { - rx_keys=new Keyframe[custom_keys.Length]; - ry_keys=new Keyframe[custom_keys.Length]; - rz_keys=new Keyframe[custom_keys.Length]; - for(int i = 0; i < custom_keys.Length; i++) - { - //オイラー角を取り出す - Vector3 eulerAngles=custom_keys[i].value.eulerAngles; - rx_keys[i]=new Keyframe(custom_keys[i].time,eulerAngles.x); - ry_keys[i]=new Keyframe(custom_keys[i].time,eulerAngles.y); - rz_keys[i]=new Keyframe(custom_keys[i].time,eulerAngles.z); - //線形補間する - rx_keys[i].tangentMode=TangentModeBothLinear; - ry_keys[i].tangentMode=TangentModeBothLinear; - rz_keys[i].tangentMode=TangentModeBothLinear; - if(i>0) - { - float tx=GetLinearTangentForRotation(rx_keys[i-1],rx_keys[i]); - float ty=GetLinearTangentForRotation(ry_keys[i-1],ry_keys[i]); - float tz=GetLinearTangentForRotation(rz_keys[i-1],rz_keys[i]); - rx_keys[i-1].outTangent=tx; - ry_keys[i-1].outTangent=ty; - rz_keys[i-1].outTangent=tz; - rx_keys[i].inTangent=tx; - ry_keys[i].inTangent=ty; - rz_keys[i].inTangent=tz; - } - } - AddDummyKeyframe(ref rx_keys); - AddDummyKeyframe(ref ry_keys); - AddDummyKeyframe(ref rz_keys); - } - - - // あるボーンに含まれるキーフレを抽出 - // これは回転のみ - void CreateKeysForRotation(MMD.VMD.VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality) - { - try - { - List mlist = format.motion_list.motion[current_bone]; - int keyframeCount = GetKeyframeCount(mlist, 3, interpolationQuality); - - QuaternionKeyframe[] r_keys = new QuaternionKeyframe[keyframeCount]; - QuaternionKeyframe r_prev_key=null; - int ir=0; - for (int i = 0; i < mlist.Count; i++) - { - const float tick_time = 1.0f / 30.0f; - float tick = mlist[i].flame_no * tick_time; - - Quaternion rotation=mlist[i].rotation; - QuaternionKeyframe r_cur_key=new QuaternionKeyframe(tick,rotation); - QuaternionKeyframe.AddBezierKeyframes(mlist[i].interpolation,3,r_prev_key,r_cur_key,interpolationQuality,ref r_keys,ref ir); - r_prev_key=r_cur_key; - } - - Keyframe[] rx_keys=null; - Keyframe[] ry_keys=null; - Keyframe[] rz_keys=null; - ToKeyframesForRotation(r_keys, ref rx_keys, ref ry_keys, ref rz_keys); - AnimationCurve curve_x = new AnimationCurve(rx_keys); - AnimationCurve curve_y = new AnimationCurve(ry_keys); - AnimationCurve curve_z = new AnimationCurve(rz_keys); - // ここで回転オイラー角をセット(補間はクォータニオン) -#if !UNITY_4_2 //4.3以降 - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.x"),curve_x); - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.y"),curve_y); - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.z"),curve_z); -#else - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.x",curve_x); - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.y",curve_y); - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.z",curve_z); -#endif - - } - catch (KeyNotFoundException) - { - //Debug.LogError("互換性のないボーンが読み込まれました:" + bone_path); - } - } - //UnityのKeyframeに変換する(移動用) - Keyframe[] ToKeyframesForLocation(FloatKeyframe[] custom_keys) - { - Keyframe[] keys=new Keyframe[custom_keys.Length]; - for(int i = 0; i < custom_keys.Length; i++) - { - keys[i]=new Keyframe(custom_keys[i].time,custom_keys[i].value); - //線形補間する - keys[i].tangentMode=TangentModeBothLinear; - if(i>0) - { - float t=GetLinearTangentForPosition(keys[i-1],keys[i]); - keys[i-1].outTangent=t; - keys[i].inTangent=t; - } - } - AddDummyKeyframe(ref keys); - return keys; - } - // 移動のみの抽出 - void CreateKeysForLocation(MMD.VMD.VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality, GameObject current_obj = null) - { - try - { - Vector3 default_position = Vector3.zero; - if(current_obj != null) - default_position = current_obj.transform.localPosition; - - List mlist = format.motion_list.motion[current_bone]; - - int keyframeCountX = GetKeyframeCount(mlist, 0, interpolationQuality); - int keyframeCountY = GetKeyframeCount(mlist, 1, interpolationQuality); - int keyframeCountZ = GetKeyframeCount(mlist, 2, interpolationQuality); - - FloatKeyframe[] lx_keys = new FloatKeyframe[keyframeCountX]; - FloatKeyframe[] ly_keys = new FloatKeyframe[keyframeCountY]; - FloatKeyframe[] lz_keys = new FloatKeyframe[keyframeCountZ]; - - FloatKeyframe lx_prev_key=null; - FloatKeyframe ly_prev_key=null; - FloatKeyframe lz_prev_key=null; - int ix=0; - int iy=0; - int iz=0; - for (int i = 0; i < mlist.Count; i++) - { - const float tick_time = 1.0f / 30.0f; - - float tick = mlist[i].flame_no * tick_time; - - FloatKeyframe lx_cur_key=new FloatKeyframe(tick,mlist[i].location.x * scale_ + default_position.x); - FloatKeyframe ly_cur_key=new FloatKeyframe(tick,mlist[i].location.y * scale_ + default_position.y); - FloatKeyframe lz_cur_key=new FloatKeyframe(tick,mlist[i].location.z * scale_ + default_position.z); - - // 各軸別々に補間が付いてる - FloatKeyframe.AddBezierKeyframes(mlist[i].interpolation,0,lx_prev_key,lx_cur_key,interpolationQuality,ref lx_keys,ref ix); - FloatKeyframe.AddBezierKeyframes(mlist[i].interpolation,1,ly_prev_key,ly_cur_key,interpolationQuality,ref ly_keys,ref iy); - FloatKeyframe.AddBezierKeyframes(mlist[i].interpolation,2,lz_prev_key,lz_cur_key,interpolationQuality,ref lz_keys,ref iz); - - lx_prev_key=lx_cur_key; - ly_prev_key=ly_cur_key; - lz_prev_key=lz_cur_key; - } - - // 回転ボーンの場合はデータが入ってないはず - if (mlist.Count != 0) - { - AnimationCurve curve_x = new AnimationCurve(ToKeyframesForLocation(lx_keys)); - AnimationCurve curve_y = new AnimationCurve(ToKeyframesForLocation(ly_keys)); - AnimationCurve curve_z = new AnimationCurve(ToKeyframesForLocation(lz_keys)); -#if !UNITY_4_2 //4.3以降 - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.x"),curve_x); - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.y"),curve_y); - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.z"),curve_z); -#else - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.x",curve_x); - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.y",curve_y); - AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.z",curve_z); -#endif - } - } - catch (KeyNotFoundException) - { - //Debug.LogError("互換性のないボーンが読み込まれました:" + current_bone); - } - } - - void CreateKeysForSkin(MMD.VMD.VMDFormat format, AnimationClip clip) - { - const float tick_time = 1f / 30f; - - // 全ての表情に打たれているキーフレームを探索 - List s; - - foreach (var skin in format.skin_list.skin) - { - s = skin.Value; - Keyframe[] keyframe = new Keyframe[skin.Value.Count]; - - // キーフレームの登録を行う - for (int i = 0; i < skin.Value.Count; i++) - { - keyframe[i] = new Keyframe(s[i].flame_no * tick_time, s[i].weight); - //線形補間する - keyframe[i].tangentMode=TangentModeBothLinear; - if(i>0) - { - float t=GetLinearTangentForPosition(keyframe[i-1],keyframe[i]); - keyframe[i-1].outTangent=t; - keyframe[i].inTangent=t; - } - } - AddDummyKeyframe(ref keyframe); - - // Z軸移動にキーフレームを打つ - AnimationCurve curve = new AnimationCurve(keyframe); -#if !UNITY_4_2 //4.3以降 - AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve("Expression/" + skin.Key,typeof(Transform),"m_LocalPosition.z"),curve); -#else - AnimationUtility.SetEditorCurve(clip,"Expression/" + skin.Key,typeof(Transform),"m_LocalPosition.z",curve); -#endif - - } - } - - // ボーンのパスを取得する - string GetBonePath(Transform transform) - { - string buf; - if (transform.parent == null) - return transform.name; - else - buf = GetBonePath(transform.parent); - return buf + "/" + transform.name; - } - - // ボーンの子供を再帰的に走査 - void FullSearchBonePath(Transform transform, Dictionary dic) - { - int count = transform.childCount; - for (int i = 0; i < count; i++) - { - Transform t = transform.GetChild(i); - FullSearchBonePath(t, dic); - } - - // オブジェクト名が足されてしまうので抜く - string buf = ""; - string[] spl = GetBonePath(transform).Split('/'); - for (int i = 1; i < spl.Length-1; i++) - buf += spl[i] + "/"; - buf += spl[spl.Length-1]; - - try - { - dic.Add(transform.name, buf); - } - catch (ArgumentException arg) - { - Debug.Log(arg.Message); - Debug.Log("An element with the same key already exists in the dictionary. -> " + transform.name); - } - - // dicには全てのボーンの名前, ボーンのパス名が入る - } - - // 無駄なカーブを登録してるけどどうするか - void FullEntryBoneAnimation(MMD.VMD.VMDFormat format, AnimationClip clip, Dictionary dic, Dictionary obj, int interpolationQuality) - { - foreach (KeyValuePair p in dic) // keyはtransformの名前, valueはパス - { - // 互いに名前の一致する場合にRigidbodyが存在するか調べたい - GameObject current_obj = null; - if(obj.ContainsKey(p.Key)){ - current_obj = obj[p.Key]; - - // Rigidbodyがある場合はキーフレの登録を無視する - var rigid = current_obj.GetComponent(); - if (rigid != null && !rigid.isKinematic) - { - continue; - } - } - - // キーフレの登録 - CreateKeysForLocation(format, clip, p.Key, p.Value, interpolationQuality, current_obj); - CreateKeysForRotation(format, clip, p.Key, p.Value, interpolationQuality); - } - } - - // とりあえず再帰的に全てのゲームオブジェクトを取得する - void GetGameObjects(Dictionary obj, GameObject assign_pmd) - { - for (int i = 0; i < assign_pmd.transform.childCount; i++) - { - var transf = assign_pmd.transform.GetChild(i); - try - { - obj.Add(transf.name, transf.gameObject); - } - catch (ArgumentException arg) - { - Debug.Log(arg.Message); - Debug.Log("An element with the same key already exists in the dictionary. -> " + transf.name); - } - - if (transf == null) continue; // ストッパー - GetGameObjects(obj, transf.gameObject); - } - } - - private float scale_ = 1.0f; - } - } -} diff --git a/Editor/MMDLoader/Private/ModelAgent.cs b/Editor/MMDLoader/Private/ModelAgent.cs index 4f4edaf..2e1be8b 100644 --- a/Editor/MMDLoader/Private/ModelAgent.cs +++ b/Editor/MMDLoader/Private/ModelAgent.cs @@ -36,7 +36,7 @@ public ModelAgent(string file_path) { /// IKを使用するか /// スケール /// PMX Baseでインポートするか - public void CreatePrefab(PMD.PMDConverter.ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale, bool is_pmx_base_import) { + public void CreatePrefab(PMDConverter.ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale, bool is_pmx_base_import) { GameObject game_object; string prefab_path; if (is_pmx_base_import) { @@ -74,7 +74,7 @@ public void CreatePrefab(PMD.PMDConverter.ShaderType shader_type, bool use_rigid header_ = PMXLoaderScript.PMD2PMX(pmd_format.head); //ゲームオブジェクトの作成 - game_object = PMD.PMDConverter.CreateGameObject(pmd_format, shader_type, use_rigidbody, use_mecanim, use_ik, scale); + game_object = PMDConverter.CreateGameObject(pmd_format, shader_type, use_rigidbody, use_mecanim, use_ik, scale); // プレファブパスの設定 prefab_path = pmd_format.folder + "/" + pmd_format.name + ".prefab"; diff --git a/Editor/MMDLoader/Private/MotionAgent.cs b/Editor/MMDLoader/Private/MotionAgent.cs index 33ebd10..31fc4ec 100644 --- a/Editor/MMDLoader/Private/MotionAgent.cs +++ b/Editor/MMDLoader/Private/MotionAgent.cs @@ -2,7 +2,6 @@ using UnityEditor; using System.Collections.Generic; using System.IO; -using MMD.VMD; namespace MMD { @@ -83,8 +82,8 @@ public string model_name {get{ } return result; }} - string file_path_; - VMDFormat.Header header_; - VMDFormat format_; + string file_path_; + VMD.VMDFormat.Header header_; + VMD.VMDFormat format_; } } \ No newline at end of file diff --git a/Editor/MMDLoader/Private/PMDConverter.cs b/Editor/MMDLoader/Private/PMDConverter.cs new file mode 100644 index 0000000..2e27b90 --- /dev/null +++ b/Editor/MMDLoader/Private/PMDConverter.cs @@ -0,0 +1,1017 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using MMD.PMD; + +namespace MMD +{ + public class PMDConverter + { + /// + /// シェーダの種類 + /// + public enum ShaderType + { + Default, /// Unityのデフォルトシェーダ + HalfLambert, /// もやっとしたLambertっぽくなる + MMDShader /// MMDっぽいシェーダ + } + + /// + /// GameObjectを作成する + /// + /// 内部形式データ + /// シェーダーの種類 + /// 剛体を使用するか + /// Mecanimを使用するか + /// IKを使用するか + /// スケール + public static GameObject CreateGameObject(PMDFormat format, ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { + PMDConverter converter = new PMDConverter(); + return converter.CreateGameObject_(format, shader_type, use_rigidbody, use_mecanim, use_ik, scale); + } + + /// + /// デフォルトコンストラクタ + /// + /// + /// ユーザーに依るインスタンス作成を禁止する + /// + private PMDConverter() {} + + private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { + format_ = format; + shader_type_ = shader_type; + use_rigidbody_ = use_rigidbody; + use_mecanim_ = use_mecanim; + use_ik_ = use_ik; + scale_ = scale; + root_game_object_ = new GameObject(format_.name); + + Mesh mesh = CreateMesh(); // メッシュの生成・設定 + Material[] materials = CreateMaterials(); // マテリアルの生成・設定 + GameObject[] bones = CreateBones(); // ボーンの生成・設定 + + // バインドポーズの作成 + BuildingBindpose(mesh, materials, bones); + + MMDEngine engine = root_game_object_.AddComponent(); + //スケール・エッジ幅 + engine.scale = scale_; + engine.outline_width = default_outline_width; + engine.material_outline_widths = Enumerable.Repeat(1.0f, materials.Length).ToArray(); + + // IKの登録 + if (use_ik_) + engine.ik_list = EntryIKSolver(bones); + + // 剛体関連 + if (use_rigidbody_) + { + try + { + var rigids = CreateRigids(bones); + AssignRigidbodyToBone(bones, rigids); + SetRigidsSettings(bones, rigids); + GameObject[] joints = SettingJointComponent(bones, rigids); + GlobalizeRigidbody(joints); + + // 非衝突グループ + List[] ignoreGroups = SettingIgnoreRigidGroups(rigids); + int[] groupTarget = GetRigidbodyGroupTargets(rigids); + + MMDEngine.Initialize(engine, groupTarget, ignoreGroups, rigids); + } + catch { } + } + + // Mecanim設定 + if (use_mecanim_) { + AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); + avatar_setting.SettingAvatar(); + + string path = format_.folder + "/"; + string name = GetFilePathString(format_.name); + string file_name = path + name + ".avatar.asset"; + avatar_setting.CreateAsset(file_name); + } else { + root_game_object_.AddComponent(); // アニメーション追加 + } + + return root_game_object_; + } + + Vector3[] EntryVertices() + { + int vcount = (int)format_.vertex_list.vert_count; + Vector3[] vpos = new Vector3[vcount]; + for (int i = 0; i < vcount; i++) + vpos[i] = format_.vertex_list.vertex[i].pos * scale_; + return vpos; + } + + Vector3[] EntryNormals() + { + int vcount = (int)format_.vertex_list.vert_count; + Vector3[] normals = new Vector3[vcount]; + for (int i = 0; i < vcount; i++) + normals[i] = format_.vertex_list.vertex[i].normal_vec; + return normals; + } + + Vector2[] EntryUVs() + { + int vcount = (int)format_.vertex_list.vert_count; + Vector2[] uvs = new Vector2[vcount]; + for (int i = 0; i < vcount; i++) + uvs[i] = format_.vertex_list.vertex[i].uv; + return uvs; + } + + BoneWeight[] EntryBoneWeights() + { + int vcount = (int)format_.vertex_list.vert_count; + BoneWeight[] weights = new BoneWeight[vcount]; + for (int i = 0; i < vcount; i++) + { + weights[i].boneIndex0 = (int)format_.vertex_list.vertex[i].bone_num[0]; + weights[i].boneIndex1 = (int)format_.vertex_list.vertex[i].bone_num[1]; + weights[i].weight0 = (float)format_.vertex_list.vertex[i].bone_weight / 100.0f; + weights[i].weight1 = 1.0f - weights[i].weight0; + } + return weights; + } + + // 頂点座標やUVなどの登録だけ + void EntryAttributesForMesh(Mesh mesh) + { + //mesh.vertexCount = (int)format_.vertex_list.vert_count; + mesh.vertices = EntryVertices(); + mesh.normals = EntryNormals(); + mesh.uv = EntryUVs(); + mesh.boneWeights = EntryBoneWeights(); + } + + void SetSubMesh(Mesh mesh) + { + // マテリアル対サブメッシュ + // サブメッシュとはマテリアルに適用したい面頂点データのこと + // 面ごとに設定するマテリアルはここ + mesh.subMeshCount = (int)format_.material_list.material_count; + + int sum = 0; + for (int i = 0; i < mesh.subMeshCount; i++) + { + int count = (int)format_.material_list.material[i].face_vert_count; + int[] indices = new int[count]; + + // 面頂点は材質0から順番に加算されている + for (int j = 0; j < count; j++) + indices[j] = format_.face_vertex_list.face_vert_index[j+sum]; + mesh.SetTriangles(indices, i); + sum += (int)format_.material_list.material[i].face_vert_count; + } + } + + // メッシュをProjectに登録 + void CreateAssetForMesh(Mesh mesh) + { + AssetDatabase.CreateAsset(mesh, format_.folder + "/" + format_.name + ".asset"); + } + + Mesh CreateMesh() + { + Mesh mesh = new Mesh(); + EntryAttributesForMesh(mesh); + SetSubMesh(mesh); + CreateAssetForMesh(mesh); + return mesh; + } + + //透過マテリアル確認(true:透過, false:不透明) + bool IsTransparentMaterial(PMD.PMDFormat.Material model_material, Texture2D texture) { + bool result = false; + result = result || (model_material.alpha < 0.98f); //0.98f以上は不透明と見做す(0.98fに影生成情報を埋め込んでいる為) + if (null != texture) { + result = result || texture.alphaIsTransparency; + } + return result; + } + + //エッジマテリアル確認(true:エッジ有り, false:無エッジ) + bool IsEdgeMaterial(PMD.PMDFormat.Material model_material) { + bool result; + if (0 == model_material.edge_flag) { + //エッジ無し + result = false; + } else { + //エッジ有りなら + result = true; + } + return result; + } + + //背面カリングマテリアル確認(true:背面カリングする, false:背面カリングしない) + bool IsCullBackMaterial(PMD.PMDFormat.Material model_material) { + bool result; + if (1.0f <= model_material.alpha) { + //不透明なら + //背面カリングする + result = true; + } else if (0.99f <= model_material.alpha) { + //不透明の両面描画なら + //背面カリングしない + result = false; + } else { + //透過なら + //背面カリングしない + result = false; + } + return result; + } + + //無影マテリアル確認(true:無影, false:影放ち) + bool IsNoCastShadowMaterial(PMD.PMDFormat.Material model_material) { + bool result; + if (0 == model_material.edge_flag) { + //エッジ無し + //無影 + result = true; + } else { + //エッジ有りなら + //影放ち + result = false; + } + return result; + } + + //影受け無しマテリアル確認(true:影受け無し, false:影受け) + bool IsNoReceiveShadowMaterial(PMD.PMDFormat.Material model_material) { + bool result; + if (0.98f == model_material.alpha) { //浮動小数点の比較だけど、0.98fとの同値確認でPMXエディタの0.98と一致したので一旦これで。 + //影受け無し(不透明度が0.98fは特別扱いで影受け無し)なら + result = true; + } else { + //影受け有りなら + result = false; + } + return result; + } + + string GetMMDShaderPath(PMD.PMDFormat.Material model_material, Texture2D texture) { + string result = "MMD/"; + if (IsTransparentMaterial(model_material, texture)) { + result += "Transparent/"; + } + result += "PMDMaterial"; + if (IsEdgeMaterial(model_material)) { + result += "-with-Outline"; + } + if (IsCullBackMaterial(model_material)) { + result += "-CullBack"; + } + if (IsNoCastShadowMaterial(model_material)) { + result += "-NoCastShadow"; + } +#if MFU_ENABLE_NO_RECEIVE_SHADOW_SHADER //影受け無しのシェーダはまだ無いので無効化 + if (IsNoReceiveShadowMaterial(model_material)) { + result += "-NoReceiveShadow"; + } +#endif //MFU_ENABLE_NO_RECEIVE_SHADOW_SHADER + return result; + } + + // 色の生成 + void EntryColors(Material[] mats) + { + // マテリアルの生成 + for (int i = 0; i < mats.Length; i++) + { + // PMDフォーマットのマテリアルを取得 + PMD.PMDFormat.Material pmdMat = format_.material_list.material[i]; + + //先にテクスチャ情報を検索 + Texture2D main_texture = null; + if (pmdMat.texture_file_name != "") { + string path = format_.folder + "/" + pmdMat.texture_file_name; + main_texture = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D; + } + + //マテリアルに設定 + switch (shader_type_) + { + case ShaderType.Default: // デフォルト + mats[i] = new Material(Shader.Find("Transparent/Diffuse")); + mats[i].color = pmdMat.diffuse_color; + Color cbuf = mats[i].color; + cbuf.a = pmdMat.alpha; // これでいいのか? + mats[i].color = cbuf; + break; + + case ShaderType.HalfLambert: // ハーフランバート + mats[i] = new Material(Shader.Find("Custom/CharModel")); + mats[i].SetFloat("_Cutoff", 1 - pmdMat.alpha); + mats[i].color = pmdMat.diffuse_color; + break; + + case ShaderType.MMDShader: + mats[i] = new Material(Shader.Find(GetMMDShaderPath(pmdMat, main_texture))); + + // シェーダに依って値が有ったり無かったりするが、設定してもエラーに為らない様なので全部設定 + mats[i].SetColor("_Color", pmdMat.diffuse_color); + mats[i].SetColor("_AmbColor", pmdMat.mirror_color); + mats[i].SetFloat("_Opacity", pmdMat.alpha); + mats[i].SetColor("_SpecularColor", pmdMat.specular_color); + mats[i].SetFloat("_Shininess", pmdMat.specularity); + // エッジ + const float c_default_scale = 0.085f; //0.085fの時にMMDと一致する様にしているので、それ以外なら補正 + mats[i].SetFloat("_OutlineWidth", default_outline_width * scale_ / c_default_scale); + mats[i].SetColor("_OutlineColor", default_outline_color); + + // ここでスフィアマップ + string path = format_.folder + "/" + pmdMat.sphere_map_name; + Texture sphere_map; + + if (System.IO.File.Exists(path)) + { // ファイルの存在を確認 + sphere_map = UnityEditor.AssetDatabase.LoadAssetAtPath(path, typeof(Texture)) as Texture; + + // 乗算と加算判定 + string ext = System.IO.Path.GetExtension(pmdMat.sphere_map_name); + switch (ext) { + case ".spa": // 加算 + mats[i].SetTexture("_SphereAddTex", sphere_map); + mats[i].SetTextureScale("_SphereAddTex", new Vector2(1, -1)); + break; + case ".sph": // 乗算 + mats[i].SetTexture("_SphereMulTex", sphere_map); + mats[i].SetTextureScale("_SphereMulTex", new Vector2(1, -1)); + break; + default: + // 加算扱い + goto case ".spa"; + } + } + + // トゥーンの位置を取得 + string toon_name = pmdMat.toon_index != 0xFF ? + format_.toon_texture_list.toon_texture_file[pmdMat.toon_index] : "toon00.bmp"; + string resource_path = UnityEditor.AssetDatabase.GetAssetPath(Shader.Find("MMD/HalfLambertOutline")); + resource_path = System.IO.Path.GetDirectoryName(resource_path); // resourceディレクトリを取得 + resource_path += "/toon/" + toon_name; + + // トゥーンが存在するか確認 + if (!System.IO.File.Exists(resource_path)) + { + // 自前トゥーンの可能性がある + resource_path = format_.folder + "/" + format_.toon_texture_list.toon_texture_file[pmdMat.toon_index]; + if (!System.IO.File.Exists(resource_path)) + { + Debug.LogError("Do not exists toon texture: " + format_.toon_texture_list.toon_texture_file[pmdMat.toon_index]); + break; + } + } + + // テクスチャの割り当て + Texture toon_tex = UnityEditor.AssetDatabase.LoadAssetAtPath(resource_path, typeof(Texture)) as Texture; + mats[i].SetTexture("_ToonTex", toon_tex); + mats[i].SetTextureScale("_ToonTex", new Vector2(1, -1)); + break; + } + + // テクスチャが空でなければ登録 + if (null != main_texture) { + mats[i].mainTexture = main_texture; + mats[i].mainTextureScale = new Vector2(1, -1); + } + } + } + + // マテリアルに必要な色などを登録 + Material[] EntryAttributesForMaterials() + { + int count = (int)format_.material_list.material_count; + Material[] mats = new Material[count]; + EntryColors(mats); + return mats; + } + + // マテリアルの登録 + void CreateAssetForMaterials(Material[] mats) + { + // 適当なフォルダに投げる + string path = format_.folder + "/Materials/"; + if (!System.IO.Directory.Exists(path)) { + AssetDatabase.CreateFolder(format_.folder, "Materials"); + } + + for (int i = 0; i < mats.Length; i++) + { + string fname = path + format_.name + "_material" + i + ".asset"; + AssetDatabase.CreateAsset(mats[i], fname); + } + } + + // マテリアルの生成 + Material[] CreateMaterials() + { + Material[] materials; + materials = EntryAttributesForMaterials(); + CreateAssetForMaterials(materials); + return materials; + } + + // 親子関係の構築 + void AttachParentsForBone(GameObject[] bones) + { + for (int i = 0; i < bones.Length; i++) + { + int index = format_.bone_list.bone[i].parent_bone_index; + if (index != 0xFFFF) + bones[i].transform.parent = bones[index].transform; + else + bones[i].transform.parent = root_game_object_.transform; + } + } + + // ボーンの位置決めや親子関係の整備など + GameObject[] EntryAttributeForBones() + { + int count = format_.bone_list.bone_count; + GameObject[] bones = new GameObject[count]; + + for (int i = 0; i < count; i++) { + bones[i] = new GameObject(format_.bone_list.bone[i].bone_name); + bones[i].transform.name = bones[i].name; + bones[i].transform.position = format_.bone_list.bone[i].bone_head_pos * scale_; + } + return bones; + } + + // ボーンの生成 + GameObject[] CreateBones() + { + GameObject[] bones; + bones = EntryAttributeForBones(); + AttachParentsForBone(bones); + CreateSkinBone(bones); + return bones; + } + + // 表情ボーンの生成を行う + void CreateSkinBone(GameObject[] bones) + { + // 表情ルートを生成してルートの子供に付ける + GameObject skin_root = new GameObject("Expression"); + if (skin_root.GetComponent() == null) + skin_root.AddComponent(); + skin_root.transform.parent = root_game_object_.transform; + + for (int i = 0; i < format_.skin_list.skin_count; i++) + { + // 表情を親ボーンに付ける + GameObject skin = new GameObject(format_.skin_list.skin_data[i].skin_name); + skin.transform.parent = skin_root.transform; + var script = skin.AddComponent(); + + // モーフの情報を入れる + AssignMorphVectorsForSkin(format_.skin_list.skin_data[i], format_.vertex_list, script); + } + } + + // モーフ情報(頂点インデックス、モーフ先頂点など)を記録する + void AssignMorphVectorsForSkin(PMD.PMDFormat.SkinData data, PMD.PMDFormat.VertexList vtxs, MMDSkinsScript script) + { + uint count = data.skin_vert_count; + int[] indices = new int[count]; + Vector3[] morph_target = new Vector3[count]; + + for (int i = 0; i < count; i++) + { + // ここで設定する + indices[i] = (int)data.skin_vert_data[i].skin_vert_index; + + // モーフ先 - 元頂点 + //morph_target[i] = (data.skin_vert_data[i].skin_vert_pos - vtxs.vertex[indices[i]].pos).normalized; + //morph_target[i] = data.skin_vert_data[i].skin_vert_pos - vtxs.vertex[indices[i]].pos; + morph_target[i] = data.skin_vert_data[i].skin_vert_pos * scale_; + } + + // スクリプトに記憶させる + script.morphTarget = morph_target; + script.targetIndices = indices; + + switch (data.skin_type) + { + case 0: + script.skinType = MMDSkinsScript.SkinType.Base; + script.gameObject.name = "base"; + break; + + case 1: + script.skinType = MMDSkinsScript.SkinType.EyeBrow; + break; + + case 2: + script.skinType = MMDSkinsScript.SkinType.Eye; + break; + + case 3: + script.skinType = MMDSkinsScript.SkinType.Lip; + break; + + case 4: + script.skinType = MMDSkinsScript.SkinType.Other; + break; + } + } + + // バインドポーズの作成 + void BuildingBindpose(Mesh mesh, Material[] materials, GameObject[] bones) + { + // 行列とかトランスフォームとか + Matrix4x4[] bindpose = new Matrix4x4[bones.Length]; + Transform[] trans = new Transform[bones.Length]; + for (int i = 0; i < bones.Length; i++) { + trans[i] = bones[i].transform; + bindpose[i] = bones[i].transform.worldToLocalMatrix; + } + + // ここで本格的な適用 + SkinnedMeshRenderer smr = root_game_object_.AddComponent() as SkinnedMeshRenderer; + mesh.bindposes = bindpose; + smr.sharedMesh = mesh; + smr.bones = trans; + smr.materials = materials; + smr.receiveShadows = false; //影を受けない + ExpressionManagerScript ems = root_game_object_.GetComponentInChildren(); + ems.mesh = mesh; + } + + // IKの登録 + // IKは基本的にスクリプトを利用 + CCDIKSolver[] EntryIKSolver(GameObject[] bones) + { + PMD.PMDFormat.IKList ik_list = format_.ik_list; + + CCDIKSolver[] iksolvers = new CCDIKSolver[ik_list.ik_data_count]; + for (int i = 0; i < ik_list.ik_data_count; i++) + { + PMD.PMDFormat.IK ik = ik_list.ik_data[i]; + + bones[ik.ik_bone_index].AddComponent(); + CCDIKSolver solver = bones[ik.ik_bone_index].GetComponent(); + solver.target = bones[ik.ik_target_bone_index].transform; + solver.controll_weight = ik.control_weight * 4; // PMDファイルは4倍らしい + solver.iterations = ik.iterations; + solver.chains = new Transform[ik.ik_chain_length]; + for (int j = 0; j < ik.ik_chain_length; j++) + solver.chains[j] = bones[ik.ik_child_bone_index[j]].transform; + + if (!(bones[ik.ik_bone_index].name.Contains("足") || bones[ik.ik_bone_index].name.Contains("つま先"))) + { + solver.enabled = false; + } + iksolvers[i] = solver; + } + + return iksolvers; + } + + // Sphere Colliderの設定 + Collider EntrySphereCollider(PMDFormat.Rigidbody rigid, GameObject obj) + { + SphereCollider collider = obj.AddComponent(); + collider.radius = rigid.shape_w * scale_; + return collider; + } + + // Box Colliderの設定 + Collider EntryBoxCollider(PMDFormat.Rigidbody rigid, GameObject obj) + { + BoxCollider collider = obj.AddComponent(); + collider.size = new Vector3( + rigid.shape_w * 2f * scale_, + rigid.shape_h * 2f * scale_, + rigid.shape_d * 2f * scale_); + return collider; + } + + // Capsule Colliderの設定 + Collider EntryCapsuleCollider(PMDFormat.Rigidbody rigid, GameObject obj) + { + CapsuleCollider collider = obj.AddComponent(); + collider.radius = rigid.shape_w * scale_; + collider.height = (rigid.shape_h + rigid.shape_w * 2) * scale_; + return collider; + } + + // 物理素材の定義 + PhysicMaterial CreatePhysicMaterial(PMDFormat.Rigidbody rigid) + { + PhysicMaterial material = new PhysicMaterial(format_.name + "_r" + rigid.rigidbody_name); + material.bounciness = rigid.rigidbody_recoil; + material.staticFriction = rigid.rigidbody_friction; + material.dynamicFriction = rigid.rigidbody_friction; + + AssetDatabase.CreateAsset(material, format_.folder + "/Physics/" + GetFilePathString(material.name) + ".asset"); + return material; + } + + // Unity側のRigidbodyの設定を行う + void UnityRigidbodySetting(PMDFormat.Rigidbody rigidbody, GameObject targetBone, bool setted=false) + { + // rigidbodyの調整 + if (!setted) + { + targetBone.rigidbody.isKinematic = (0 == rigidbody.rigidbody_type); + targetBone.rigidbody.mass = Mathf.Max(float.Epsilon, rigidbody.rigidbody_weight); + targetBone.rigidbody.drag = rigidbody.rigidbody_pos_dim; + targetBone.rigidbody.angularDrag = rigidbody.rigidbody_rot_dim; + } + else + { + // Rigidbodyはボーンに対して適用されるので複数ある場合は平均を取る + targetBone.rigidbody.mass += rigidbody.rigidbody_weight; + targetBone.rigidbody.drag += rigidbody.rigidbody_pos_dim; + targetBone.rigidbody.angularDrag += rigidbody.rigidbody_rot_dim; + targetBone.rigidbody.mass *= 0.5f; + targetBone.rigidbody.drag *= 0.5f; + targetBone.rigidbody.angularDrag *= 0.5f; + } + } + + // 剛体の値を代入する + void SetRigidsSettings(GameObject[] bones, GameObject[] rigid) + { + PMDFormat.RigidbodyList list = format_.rigidbody_list; + for (int i = 0; i < list.rigidbody_count; i++) // iは剛体番号 + { + // 剛体の関連ボーンのインデックス + int rigidRefIndex = list.rigidbody[i].rigidbody_rel_bone_index; + + // ローカル座標の確定 + Vector3 localPos = list.rigidbody[i].pos_pos * scale_;// - rigid[i].transform.position; + + // ここで位置の決定 + if (rigidRefIndex >= ushort.MaxValue) + { + // 関連ボーン無し + if (rigid[i].rigidbody == null) + rigid[i].AddComponent(); + UnityRigidbodySetting(list.rigidbody[i], rigid[i]); + rigid[i].transform.localPosition = localPos; + + // 関連ボーンなしの剛体はセンターボーンに接続している + rigid[i].transform.position = localPos + format_.bone_list.bone[0].bone_head_pos * scale_; + // 回転の値を決める + Vector3 rot = list.rigidbody[i].pos_rot * Mathf.Rad2Deg; + rigid[i].transform.rotation = Quaternion.Euler(rot); + } + else + // 関連ボーン有り + { // とりあえずここで剛体を追加・設定 + if (bones[rigidRefIndex].rigidbody == null) + bones[rigidRefIndex].AddComponent(); + UnityRigidbodySetting(list.rigidbody[i], bones[rigidRefIndex]); + rigid[i].transform.localPosition = localPos; + // 回転の値を決める + Vector3 rot = list.rigidbody[i].pos_rot * Mathf.Rad2Deg; + rigid[i].transform.rotation = Quaternion.Euler(rot); + } + + } + } + + // 剛体の生成 + GameObject[] CreateRigids(GameObject[] bones) + { + PMDFormat.RigidbodyList list = format_.rigidbody_list; + if (!System.IO.Directory.Exists(System.IO.Path.Combine(format_.folder, "Physics"))) + { + AssetDatabase.CreateFolder(format_.folder, "Physics"); + } + + // 剛体の登録 + GameObject[] rigid = new GameObject[list.rigidbody_count]; + for (int i = 0; i < list.rigidbody_count; i++) + { + rigid[i] = new GameObject("r" + list.rigidbody[i].rigidbody_name); + //rigid[i].AddComponent(); // 剛体本体にはrigidbodyは適用しない + + // 各種Colliderの設定 + Collider collider = null; + switch (list.rigidbody[i].shape_type) + { + case 0: + collider = EntrySphereCollider(list.rigidbody[i], rigid[i]); + break; + + case 1: + collider = EntryBoxCollider(list.rigidbody[i], rigid[i]); + break; + + case 2: + collider = EntryCapsuleCollider(list.rigidbody[i], rigid[i]); + break; + } + + // マテリアルの設定 + collider.material = CreatePhysicMaterial(list.rigidbody[i]); + } + return rigid; + } + + // ジョインに依って接続している(されている)剛体番号を検索する + int SearchConnectRigidByJoint(int rigidIndex) + { + for (int i = 0; i < format_.rigidbody_joint_list.joint_count; i++) + { + int joint_rigidbody_a = (int)format_.rigidbody_joint_list.joint[i].joint_rigidbody_a; + int joint_rigidbody_b = (int)format_.rigidbody_joint_list.joint[i].joint_rigidbody_b; + if (joint_rigidbody_b == rigidIndex) + { + return joint_rigidbody_a; + } + else if (joint_rigidbody_a == rigidIndex) + { + return joint_rigidbody_b; + } + } + // 接続剛体は発見出来ず + return -1; + } + + // 関連ボーンなしの剛体から親のボーンを探してくる + // rigidIndexは剛体番号 + int GetTargetRigidBone(int rigidIndex) + { + // 接続剛体Aを探す + int targetRigid = SearchConnectRigidByJoint(rigidIndex); + + // 接続剛体Aの関連ボーンを探す + int ind = format_.rigidbody_list.rigidbody[targetRigid].rigidbody_rel_bone_index; + + // MaxValueを引けば接続剛体Aの関連ボーンに接続されるようになっている + if (ind >= ushort.MaxValue) + format_.rigidbody_list.rigidbody[rigidIndex].rigidbody_rel_bone_index = ushort.MaxValue + (ushort)ind; + + return (int)ind; + } + + // 剛体ボーンを + void AssignRigidbodyToBone(GameObject[] bones, GameObject[] rigids) + { + // 剛体の数だけ回す + for (int i = 0; i < rigids.Length; i++) + { + // 剛体を親ボーンに格納 + int refIndex = format_.rigidbody_list.rigidbody[i].rigidbody_rel_bone_index; + if (refIndex != ushort.MaxValue) + { // 65535が最大値 + rigids[i].transform.parent = bones[refIndex].transform; + } + else + { + // ジョイントから接続剛体B=現在の剛体名で探し出す + int boneIndex = GetTargetRigidBone(i); + + // 接続剛体Aの関連ボーンに剛体を接続 + rigids[i].transform.parent = bones[boneIndex].transform; + } + } + } + + // 移動や回転制限 + void SetMotionAngularLock(PMDFormat.Joint joint, ConfigurableJoint conf) + { + SoftJointLimit jlim; + + // Motionの固定 + if (joint.constrain_pos_1.x == 0f && joint.constrain_pos_2.x == 0f) + conf.xMotion = ConfigurableJointMotion.Locked; + else + conf.xMotion = ConfigurableJointMotion.Limited; + + if (joint.constrain_pos_1.y == 0f && joint.constrain_pos_2.y == 0f) + conf.yMotion = ConfigurableJointMotion.Locked; + else + conf.yMotion = ConfigurableJointMotion.Limited; + + if (joint.constrain_pos_1.z == 0f && joint.constrain_pos_2.z == 0f) + conf.zMotion = ConfigurableJointMotion.Locked; + else + conf.zMotion = ConfigurableJointMotion.Limited; + + // 角度の固定 + if (joint.constrain_rot_1.x == 0f && joint.constrain_rot_2.x == 0f) + conf.angularXMotion = ConfigurableJointMotion.Locked; + else + { + conf.angularXMotion = ConfigurableJointMotion.Limited; + float hlim = Mathf.Max(-joint.constrain_rot_1.x, -joint.constrain_rot_2.x); //回転方向が逆なので負数 + float llim = Mathf.Min(-joint.constrain_rot_1.x, -joint.constrain_rot_2.x); + SoftJointLimit jhlim = new SoftJointLimit(); + jhlim.limit = Mathf.Clamp(hlim * Mathf.Rad2Deg, -180.0f, 180.0f); + conf.highAngularXLimit = jhlim; + + SoftJointLimit jllim = new SoftJointLimit(); + jllim.limit = Mathf.Clamp(llim * Mathf.Rad2Deg, -180.0f, 180.0f); + conf.lowAngularXLimit = jllim; + } + + if (joint.constrain_rot_1.y == 0f && joint.constrain_rot_2.y == 0f) + conf.angularYMotion = ConfigurableJointMotion.Locked; + else + { + // 値がマイナスだとエラーが出るので注意 + conf.angularYMotion = ConfigurableJointMotion.Limited; + float lim = Mathf.Min(Mathf.Abs(joint.constrain_rot_1.y), Mathf.Abs(joint.constrain_rot_2.y));//絶対値の小さい方 + jlim = new SoftJointLimit(); + jlim.limit = lim * Mathf.Clamp(Mathf.Rad2Deg, 0.0f, 180.0f); + conf.angularYLimit = jlim; + } + + if (joint.constrain_rot_1.z == 0f && joint.constrain_rot_2.z == 0f) + conf.angularZMotion = ConfigurableJointMotion.Locked; + else + { + conf.angularZMotion = ConfigurableJointMotion.Limited; + float lim = Mathf.Min(Mathf.Abs(-joint.constrain_rot_1.z), Mathf.Abs(-joint.constrain_rot_2.z));//絶対値の小さい方//回転方向が逆なので負数 + jlim = new SoftJointLimit(); + jlim.limit = Mathf.Clamp(lim * Mathf.Rad2Deg, 0.0f, 180.0f); + conf.angularZLimit = jlim; + } + } + + // ばねの設定など + void SetDrive(PMDFormat.Joint joint, ConfigurableJoint conf) + { + JointDrive drive; + + // Position + if (joint.spring_pos.x != 0f) + { + drive = new JointDrive(); + drive.positionSpring = joint.spring_pos.x * scale_; + conf.xDrive = drive; + } + if (joint.spring_pos.y != 0f) + { + drive = new JointDrive(); + drive.positionSpring = joint.spring_pos.y * scale_; + conf.yDrive = drive; + } + if (joint.spring_pos.z != 0f) + { + drive = new JointDrive(); + drive.positionSpring = joint.spring_pos.z * scale_; + conf.zDrive = drive; + } + + // Angular + if (joint.spring_rot.x != 0f) + { + drive = new JointDrive(); + drive.mode = JointDriveMode.PositionAndVelocity; + drive.positionSpring = joint.spring_rot.x; + conf.angularXDrive = drive; + } + if (joint.spring_rot.y != 0f || joint.spring_rot.z != 0f) + { + drive = new JointDrive(); + drive.mode = JointDriveMode.PositionAndVelocity; + drive.positionSpring = (joint.spring_rot.y + joint.spring_rot.z) * 0.5f; + conf.angularYZDrive = drive; + } + } + + // ConfigurableJointの値を設定する + void SetAttributeConfigurableJoint(PMDFormat.Joint joint, ConfigurableJoint conf) + { + SetMotionAngularLock(joint, conf); + SetDrive(joint, conf); + } + + // ConfigurableJointの設定 + // 先に設定してからFixedJointを設定する + GameObject[] SetupConfigurableJoint(GameObject[] rigids) + { + List result_list = new List(); + foreach (PMDFormat.Joint joint in format_.rigidbody_joint_list.joint) { + //相互接続する剛体の取得 + Transform transform_a = rigids[joint.joint_rigidbody_a].transform; + Transform transform_b = rigids[joint.joint_rigidbody_b].transform; + Rigidbody rigidbody_a = transform_a.rigidbody; + if (null == rigidbody_a) { + rigidbody_a = transform_a.parent.rigidbody; + } + Rigidbody rigidbody_b = transform_b.rigidbody; + if (null == rigidbody_b) { + rigidbody_b = transform_b.parent.rigidbody; + } + if (rigidbody_a != rigidbody_b) { + //接続する剛体が同じ剛体を指さないなら + //(本来ならPMDの設定が間違っていない限り同一を指す事は無いが、MFUでは関連ボーンを持たない剛体はセンターボーンに纏められる為に依り起こり得る) + //ジョイント設定 + ConfigurableJoint config_joint = rigidbody_b.gameObject.AddComponent(); + config_joint.connectedBody = rigidbody_a; + SetAttributeConfigurableJoint(joint, config_joint); + + result_list.Add(config_joint.gameObject); + } + } + return result_list.ToArray(); + } + + // ジョイントの設定 + // ジョイントはボーンに対して適用される + GameObject[] SettingJointComponent(GameObject[] bones, GameObject[] rigids) + { + // ConfigurableJointの設定 + GameObject[] joints = SetupConfigurableJoint(rigids); + return joints; + } + + // 剛体のグローバル座標化 + void GlobalizeRigidbody(GameObject[] joints) + { + if ((null != joints) && (0 < joints.Length)) { + // 物理演算ルートを生成してルートの子供に付ける + GameObject physics_root = new GameObject("Physics"); + PhysicsManager physics_manager = physics_root.AddComponent(); + physics_root.transform.parent = root_game_object_.transform; + Transform physics_root_transform = physics_root.transform; + + // PhysicsManagerに移動前の状態を覚えさせる(幾つか重複しているので重複は削除) + physics_manager.connect_bone_list = joints.Select(x=>x.gameObject) + .Distinct() + .Select(x=>new PhysicsManager.ConnectBone(x, x.transform.parent.gameObject)) + .ToArray(); + + //isKinematicで無くConfigurableJointを持つ場合はグローバル座標化 + foreach (ConfigurableJoint joint in joints.Where(x=>!x.GetComponent().isKinematic) + .Select(x=>x.GetComponent())) { + joint.transform.parent = physics_root_transform; + } + } + } + + // 非衝突剛体の設定 + List[] SettingIgnoreRigidGroups(GameObject[] rigids) + { + // 非衝突グループ用リストの初期化 + const int MaxGroup = 16; // グループの最大数 + List[] ignoreRigid = new List[MaxGroup]; + for (int i = 0; i < 16; i++) ignoreRigid[i] = new List(); + + // それぞれの剛体が所属している非衝突グループを追加していく + PMDFormat.RigidbodyList list = format_.rigidbody_list; + for (int i = 0; i < list.rigidbody_count; i++) + ignoreRigid[list.rigidbody[i].rigidbody_group_index].Add(i); + return ignoreRigid; + } + + // グループターゲット + int[] GetRigidbodyGroupTargets(GameObject[] rigids) + { + int[] result = new int[rigids.Length]; + for (int i = 0; i < rigids.Length; i++) + { + result[i] = format_.rigidbody_list.rigidbody[i].rigidbody_group_target; + } + return result; + } + + /// + /// ファイルパス文字列の取得 + /// + /// ファイルパスに使用可能な文字列 + /// ファイルパスに使用したい文字列 + private static string GetFilePathString(string src) { + return src.Replace('\\', '\') + .Replace('/', '/') + .Replace(':', ':') + .Replace('*', '*') + .Replace('?', '?') + .Replace('"', '”') + .Replace('<', '<') + .Replace('>', '>') + .Replace('|', '|') + .Replace("\n", string.Empty) + .Replace("\r", string.Empty); + } + + static float default_outline_width = 0.2f; //標準エッジ幅 + static Color default_outline_color = Color.black; //標準エッジ色 + + GameObject root_game_object_; + PMDFormat format_; + ShaderType shader_type_; + bool use_rigidbody_; + bool use_mecanim_; + bool use_ik_; + float scale_; + } +} diff --git a/Editor/MMDLoader/Private/VMDConverter.cs b/Editor/MMDLoader/Private/VMDConverter.cs new file mode 100644 index 0000000..53141cc --- /dev/null +++ b/Editor/MMDLoader/Private/VMDConverter.cs @@ -0,0 +1,540 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using MMD.VMD; + +namespace MMD +{ + public class VMDConverter + { + /// + /// AnimationClipを作成する + /// + /// 内部形式データ + /// 使用するPMDのGameObject + /// 補完曲線品質 + public static AnimationClip CreateAnimationClip(VMDFormat format, GameObject assign_pmd, int interpolationQuality) { + VMDConverter converter = new VMDConverter(); + return converter.CreateAnimationClip_(format, assign_pmd, interpolationQuality); + } + + /// + /// デフォルトコンストラクタ + /// + /// + /// ユーザーに依るインスタンス作成を禁止する + /// + private VMDConverter() {} + + // クリップをアニメーションに登録する + private AnimationClip CreateAnimationClip_(MMD.VMD.VMDFormat format, GameObject assign_pmd, int interpolationQuality) + { + //スケール設定 + scale_ = 1.0f; + if (assign_pmd) { + MMDEngine engine = assign_pmd.GetComponent(); + if (engine) { + scale_ = engine.scale; + } + } + + //Animation anim = assign_pmd.GetComponent(); + + // クリップの作成 + AnimationClip clip = new AnimationClip(); + clip.name = assign_pmd.name + "_" + format.name; + + Dictionary bone_path = new Dictionary(); + Dictionary gameobj = new Dictionary(); + GetGameObjects(gameobj, assign_pmd); // 親ボーン下のGameObjectを取得 + FullSearchBonePath(assign_pmd.transform, bone_path); + FullEntryBoneAnimation(format, clip, bone_path, gameobj, interpolationQuality); + + CreateKeysForSkin(format, clip); // 表情の追加 + + return clip; + } + + // ベジェハンドルを取得する + // 0~127の値を 0f~1fとして返す + static Vector2 GetBezierHandle(byte[] interpolation, int type, int ab) + { + // 0=X, 1=Y, 2=Z, 3=R + // abはa?かb?のどちらを使いたいか + Vector2 bezierHandle = new Vector2((float)interpolation[ab*8+type], (float)interpolation[ab*8+4+type]); + return bezierHandle/127f; + } + // p0:(0f,0f),p3:(1f,1f)のベジェ曲線上の点を取得する + // tは0~1の範囲 + static Vector2 SampleBezier(Vector2 bezierHandleA, Vector2 bezierHandleB, float t) + { + Vector2 p0 = Vector2.zero; + Vector2 p1 = bezierHandleA; + Vector2 p2 = bezierHandleB; + Vector2 p3 = new Vector2(1f,1f); + + Vector2 q0 = Vector2.Lerp(p0, p1, t); + Vector2 q1 = Vector2.Lerp(p1, p2, t); + Vector2 q2 = Vector2.Lerp(p2, p3, t); + + Vector2 r0 = Vector2.Lerp(q0, q1, t); + Vector2 r1 = Vector2.Lerp(q1, q2, t); + + Vector2 s0 = Vector2.Lerp(r0, r1, t); + return s0; + } + // 補間曲線が線形補間と等価か + static bool IsLinear(byte[] interpolation, int type) + { + byte ax=interpolation[0*8+type]; + byte ay=interpolation[0*8+4+type]; + byte bx=interpolation[1*8+type]; + byte by=interpolation[1*8+4+type]; + return (ax == ay) && (bx == by); + } + // 補間曲線の近似のために追加するキーフレームを含めたキーフレーム数を取得する + int GetKeyframeCount(List mlist, int type, int interpolationQuality) + { + int count = 0; + for(int i = 0; i < mlist.Count; i++) + { + if(i>0 && !IsLinear(mlist[i].interpolation, type)) + { + count += interpolationQuality;//Interpolation Keyframes + } + else + { + count += 1;//Keyframe + } + } + return count; + } + //キーフレームが1つの時、ダミーキーフレームを追加する + void AddDummyKeyframe(ref Keyframe[] keyframes) + { + if(keyframes.Length==1) + { + Keyframe[] newKeyframes=new Keyframe[2]; + newKeyframes[0]=keyframes[0]; + newKeyframes[1]=keyframes[0]; + newKeyframes[1].time+=0.001f/60f;//1[ms] + newKeyframes[0].outTangent=0f; + newKeyframes[1].inTangent=0f; + keyframes=newKeyframes; + } + } + // 任意の型のvalueを持つキーフレーム + abstract class CustomKeyframe + { + public CustomKeyframe(float time,Type value) + { + this.time=time; + this.value=value; + } + public float time{ get; set; } + public Type value{ get; set; } + } + // float型のvalueを持つキーフレーム + class FloatKeyframe:CustomKeyframe + { + public FloatKeyframe(float time,float value):base(time,value) + { + } + // 線形補間 + public static FloatKeyframe Lerp(FloatKeyframe from, FloatKeyframe to,Vector2 t) + { + return new FloatKeyframe( + Mathf.Lerp(from.time,to.time,t.x), + Mathf.Lerp(from.value,to.value,t.y) + ); + } + // ベジェを線形補間で近似したキーフレームを追加する + public static void AddBezierKeyframes(byte[] interpolation, int type, + FloatKeyframe prev_keyframe,FloatKeyframe cur_keyframe, int interpolationQuality, + ref FloatKeyframe[] keyframes,ref int index) + { + if(prev_keyframe==null || IsLinear(interpolation,type)) + { + keyframes[index++]=cur_keyframe; + } + else + { + Vector2 bezierHandleA=GetBezierHandle(interpolation,type,0); + Vector2 bezierHandleB=GetBezierHandle(interpolation,type,1); + int sampleCount = interpolationQuality; + for(int j = 0; j < sampleCount; j++) + { + float t = (j+1)/(float)sampleCount; + Vector2 sample = SampleBezier(bezierHandleA,bezierHandleB,t); + keyframes[index++] = FloatKeyframe.Lerp(prev_keyframe,cur_keyframe,sample); + } + } + } + } + // Quaternion型のvalueを持つキーフレーム + class QuaternionKeyframe:CustomKeyframe + { + public QuaternionKeyframe(float time,Quaternion value):base(time,value) + { + } + // 線形補間 + public static QuaternionKeyframe Lerp(QuaternionKeyframe from, QuaternionKeyframe to,Vector2 t) + { + return new QuaternionKeyframe( + Mathf.Lerp(from.time,to.time,t.x), + Quaternion.Slerp(from.value,to.value,t.y) + ); + } + // ベジェを線形補間で近似したキーフレームを追加する + public static void AddBezierKeyframes(byte[] interpolation, int type, + QuaternionKeyframe prev_keyframe,QuaternionKeyframe cur_keyframe, int interpolationQuality, + ref QuaternionKeyframe[] keyframes,ref int index) + { + if(prev_keyframe==null || IsLinear(interpolation,type)) + { + keyframes[index++]=cur_keyframe; + } + else + { + Vector2 bezierHandleA=GetBezierHandle(interpolation,type,0); + Vector2 bezierHandleB=GetBezierHandle(interpolation,type,1); + int sampleCount = interpolationQuality; + for(int j = 0; j < sampleCount; j++) + { + float t=(j+1)/(float)sampleCount; + Vector2 sample = SampleBezier(bezierHandleA,bezierHandleB,t); + keyframes[index++] = QuaternionKeyframe.Lerp(prev_keyframe,cur_keyframe,sample); + } + } + } + + } + + //移動の線形補間用tangentを求める + float GetLinearTangentForPosition(Keyframe from_keyframe,Keyframe to_keyframe) + { + return (to_keyframe.value-from_keyframe.value)/(to_keyframe.time-from_keyframe.time); + } + //-359~+359度の範囲を等価な0~359度へ変換する。 + float Mod360(float angle) + { + //剰余演算の代わりに加算にする + return (angle<0)?(angle+360f):(angle); + } + //回転の線形補間用tangentを求める + float GetLinearTangentForRotation(Keyframe from_keyframe,Keyframe to_keyframe) + { + float tv=Mod360(to_keyframe.value); + float fv=Mod360(from_keyframe.value); + float delta_value=Mod360(tv-fv); + //180度を越える場合は逆回転 + if(delta_value<180f) + { + return delta_value/(to_keyframe.time-from_keyframe.time); + } + else + { + return (delta_value-360f)/(to_keyframe.time-from_keyframe.time); + } + } + //アニメーションエディタでBothLinearを選択したときの値 + private const int TangentModeBothLinear=21; + + //UnityのKeyframeに変換する(回転用) + void ToKeyframesForRotation(QuaternionKeyframe[] custom_keys,ref Keyframe[] rx_keys,ref Keyframe[] ry_keys,ref Keyframe[] rz_keys) + { + rx_keys=new Keyframe[custom_keys.Length]; + ry_keys=new Keyframe[custom_keys.Length]; + rz_keys=new Keyframe[custom_keys.Length]; + for(int i = 0; i < custom_keys.Length; i++) + { + //オイラー角を取り出す + Vector3 eulerAngles=custom_keys[i].value.eulerAngles; + rx_keys[i]=new Keyframe(custom_keys[i].time,eulerAngles.x); + ry_keys[i]=new Keyframe(custom_keys[i].time,eulerAngles.y); + rz_keys[i]=new Keyframe(custom_keys[i].time,eulerAngles.z); + //線形補間する + rx_keys[i].tangentMode=TangentModeBothLinear; + ry_keys[i].tangentMode=TangentModeBothLinear; + rz_keys[i].tangentMode=TangentModeBothLinear; + if(i>0) + { + float tx=GetLinearTangentForRotation(rx_keys[i-1],rx_keys[i]); + float ty=GetLinearTangentForRotation(ry_keys[i-1],ry_keys[i]); + float tz=GetLinearTangentForRotation(rz_keys[i-1],rz_keys[i]); + rx_keys[i-1].outTangent=tx; + ry_keys[i-1].outTangent=ty; + rz_keys[i-1].outTangent=tz; + rx_keys[i].inTangent=tx; + ry_keys[i].inTangent=ty; + rz_keys[i].inTangent=tz; + } + } + AddDummyKeyframe(ref rx_keys); + AddDummyKeyframe(ref ry_keys); + AddDummyKeyframe(ref rz_keys); + } + + + // あるボーンに含まれるキーフレを抽出 + // これは回転のみ + void CreateKeysForRotation(MMD.VMD.VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality) + { + try + { + List mlist = format.motion_list.motion[current_bone]; + int keyframeCount = GetKeyframeCount(mlist, 3, interpolationQuality); + + QuaternionKeyframe[] r_keys = new QuaternionKeyframe[keyframeCount]; + QuaternionKeyframe r_prev_key=null; + int ir=0; + for (int i = 0; i < mlist.Count; i++) + { + const float tick_time = 1.0f / 30.0f; + float tick = mlist[i].flame_no * tick_time; + + Quaternion rotation=mlist[i].rotation; + QuaternionKeyframe r_cur_key=new QuaternionKeyframe(tick,rotation); + QuaternionKeyframe.AddBezierKeyframes(mlist[i].interpolation,3,r_prev_key,r_cur_key,interpolationQuality,ref r_keys,ref ir); + r_prev_key=r_cur_key; + } + + Keyframe[] rx_keys=null; + Keyframe[] ry_keys=null; + Keyframe[] rz_keys=null; + ToKeyframesForRotation(r_keys, ref rx_keys, ref ry_keys, ref rz_keys); + AnimationCurve curve_x = new AnimationCurve(rx_keys); + AnimationCurve curve_y = new AnimationCurve(ry_keys); + AnimationCurve curve_z = new AnimationCurve(rz_keys); + // ここで回転オイラー角をセット(補間はクォータニオン) +#if !UNITY_4_2 //4.3以降 + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.x"),curve_x); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.y"),curve_y); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"localEulerAngles.z"),curve_z); +#else + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.x",curve_x); + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.y",curve_y); + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"localEulerAngles.z",curve_z); +#endif + + } + catch (KeyNotFoundException) + { + //Debug.LogError("互換性のないボーンが読み込まれました:" + bone_path); + } + } + //UnityのKeyframeに変換する(移動用) + Keyframe[] ToKeyframesForLocation(FloatKeyframe[] custom_keys) + { + Keyframe[] keys=new Keyframe[custom_keys.Length]; + for(int i = 0; i < custom_keys.Length; i++) + { + keys[i]=new Keyframe(custom_keys[i].time,custom_keys[i].value); + //線形補間する + keys[i].tangentMode=TangentModeBothLinear; + if(i>0) + { + float t=GetLinearTangentForPosition(keys[i-1],keys[i]); + keys[i-1].outTangent=t; + keys[i].inTangent=t; + } + } + AddDummyKeyframe(ref keys); + return keys; + } + // 移動のみの抽出 + void CreateKeysForLocation(MMD.VMD.VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality, GameObject current_obj = null) + { + try + { + Vector3 default_position = Vector3.zero; + if(current_obj != null) + default_position = current_obj.transform.localPosition; + + List mlist = format.motion_list.motion[current_bone]; + + int keyframeCountX = GetKeyframeCount(mlist, 0, interpolationQuality); + int keyframeCountY = GetKeyframeCount(mlist, 1, interpolationQuality); + int keyframeCountZ = GetKeyframeCount(mlist, 2, interpolationQuality); + + FloatKeyframe[] lx_keys = new FloatKeyframe[keyframeCountX]; + FloatKeyframe[] ly_keys = new FloatKeyframe[keyframeCountY]; + FloatKeyframe[] lz_keys = new FloatKeyframe[keyframeCountZ]; + + FloatKeyframe lx_prev_key=null; + FloatKeyframe ly_prev_key=null; + FloatKeyframe lz_prev_key=null; + int ix=0; + int iy=0; + int iz=0; + for (int i = 0; i < mlist.Count; i++) + { + const float tick_time = 1.0f / 30.0f; + + float tick = mlist[i].flame_no * tick_time; + + FloatKeyframe lx_cur_key=new FloatKeyframe(tick,mlist[i].location.x * scale_ + default_position.x); + FloatKeyframe ly_cur_key=new FloatKeyframe(tick,mlist[i].location.y * scale_ + default_position.y); + FloatKeyframe lz_cur_key=new FloatKeyframe(tick,mlist[i].location.z * scale_ + default_position.z); + + // 各軸別々に補間が付いてる + FloatKeyframe.AddBezierKeyframes(mlist[i].interpolation,0,lx_prev_key,lx_cur_key,interpolationQuality,ref lx_keys,ref ix); + FloatKeyframe.AddBezierKeyframes(mlist[i].interpolation,1,ly_prev_key,ly_cur_key,interpolationQuality,ref ly_keys,ref iy); + FloatKeyframe.AddBezierKeyframes(mlist[i].interpolation,2,lz_prev_key,lz_cur_key,interpolationQuality,ref lz_keys,ref iz); + + lx_prev_key=lx_cur_key; + ly_prev_key=ly_cur_key; + lz_prev_key=lz_cur_key; + } + + // 回転ボーンの場合はデータが入ってないはず + if (mlist.Count != 0) + { + AnimationCurve curve_x = new AnimationCurve(ToKeyframesForLocation(lx_keys)); + AnimationCurve curve_y = new AnimationCurve(ToKeyframesForLocation(ly_keys)); + AnimationCurve curve_z = new AnimationCurve(ToKeyframesForLocation(lz_keys)); +#if !UNITY_4_2 //4.3以降 + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.x"),curve_x); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.y"),curve_y); + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve(bone_path,typeof(Transform),"m_LocalPosition.z"),curve_z); +#else + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.x",curve_x); + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.y",curve_y); + AnimationUtility.SetEditorCurve(clip,bone_path,typeof(Transform),"m_LocalPosition.z",curve_z); +#endif + } + } + catch (KeyNotFoundException) + { + //Debug.LogError("互換性のないボーンが読み込まれました:" + current_bone); + } + } + + void CreateKeysForSkin(MMD.VMD.VMDFormat format, AnimationClip clip) + { + const float tick_time = 1f / 30f; + + // 全ての表情に打たれているキーフレームを探索 + List s; + + foreach (var skin in format.skin_list.skin) + { + s = skin.Value; + Keyframe[] keyframe = new Keyframe[skin.Value.Count]; + + // キーフレームの登録を行う + for (int i = 0; i < skin.Value.Count; i++) + { + keyframe[i] = new Keyframe(s[i].flame_no * tick_time, s[i].weight); + //線形補間する + keyframe[i].tangentMode=TangentModeBothLinear; + if(i>0) + { + float t=GetLinearTangentForPosition(keyframe[i-1],keyframe[i]); + keyframe[i-1].outTangent=t; + keyframe[i].inTangent=t; + } + } + AddDummyKeyframe(ref keyframe); + + // Z軸移動にキーフレームを打つ + AnimationCurve curve = new AnimationCurve(keyframe); +#if !UNITY_4_2 //4.3以降 + AnimationUtility.SetEditorCurve(clip,EditorCurveBinding.FloatCurve("Expression/" + skin.Key,typeof(Transform),"m_LocalPosition.z"),curve); +#else + AnimationUtility.SetEditorCurve(clip,"Expression/" + skin.Key,typeof(Transform),"m_LocalPosition.z",curve); +#endif + + } + } + + // ボーンのパスを取得する + string GetBonePath(Transform transform) + { + string buf; + if (transform.parent == null) + return transform.name; + else + buf = GetBonePath(transform.parent); + return buf + "/" + transform.name; + } + + // ボーンの子供を再帰的に走査 + void FullSearchBonePath(Transform transform, Dictionary dic) + { + int count = transform.childCount; + for (int i = 0; i < count; i++) + { + Transform t = transform.GetChild(i); + FullSearchBonePath(t, dic); + } + + // オブジェクト名が足されてしまうので抜く + string buf = ""; + string[] spl = GetBonePath(transform).Split('/'); + for (int i = 1; i < spl.Length-1; i++) + buf += spl[i] + "/"; + buf += spl[spl.Length-1]; + + try + { + dic.Add(transform.name, buf); + } + catch (System.ArgumentException arg) + { + Debug.Log(arg.Message); + Debug.Log("An element with the same key already exists in the dictionary. -> " + transform.name); + } + + // dicには全てのボーンの名前, ボーンのパス名が入る + } + + // 無駄なカーブを登録してるけどどうするか + void FullEntryBoneAnimation(MMD.VMD.VMDFormat format, AnimationClip clip, Dictionary dic, Dictionary obj, int interpolationQuality) + { + foreach (KeyValuePair p in dic) // keyはtransformの名前, valueはパス + { + // 互いに名前の一致する場合にRigidbodyが存在するか調べたい + GameObject current_obj = null; + if(obj.ContainsKey(p.Key)){ + current_obj = obj[p.Key]; + + // Rigidbodyがある場合はキーフレの登録を無視する + var rigid = current_obj.GetComponent(); + if (rigid != null && !rigid.isKinematic) + { + continue; + } + } + + // キーフレの登録 + CreateKeysForLocation(format, clip, p.Key, p.Value, interpolationQuality, current_obj); + CreateKeysForRotation(format, clip, p.Key, p.Value, interpolationQuality); + } + } + + // とりあえず再帰的に全てのゲームオブジェクトを取得する + void GetGameObjects(Dictionary obj, GameObject assign_pmd) + { + for (int i = 0; i < assign_pmd.transform.childCount; i++) + { + var transf = assign_pmd.transform.GetChild(i); + try + { + obj.Add(transf.name, transf.gameObject); + } + catch (System.ArgumentException arg) + { + Debug.Log(arg.Message); + Debug.Log("An element with the same key already exists in the dictionary. -> " + transf.name); + } + + if (transf == null) continue; // ストッパー + GetGameObjects(obj, transf.gameObject); + } + } + + private float scale_ = 1.0f; + } +} From e6fadc35cb9b5926f13724b1e92a1d5c2a20e44d Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Tue, 31 Dec 2013 21:23:53 +0900 Subject: [PATCH 36/37] =?UTF-8?q?=E6=B1=8E=E7=94=A8=E3=82=A2=E3=83=90?= =?UTF-8?q?=E3=82=BF=E3=83=BC=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Config/Config.cs | 4 +- Editor/Inspector/PMDInspector.cs | 8 ++-- Editor/MMDLoader/PMDLoaderWindow.cs | 26 ++++++------- .../MMDLoader/Private/AvatarSettingScript.cs | 30 +++++++++++++-- Editor/MMDLoader/Private/ModelAgent.cs | 7 ++-- Editor/MMDLoader/Private/PMDConverter.cs | 2 +- Editor/MMDLoader/Private/PMXConverter.cs | 38 +++++++++++++------ Editor/MMDLoader/Private/VMDConverter.cs | 21 ++++++++++ 8 files changed, 97 insertions(+), 39 deletions(-) diff --git a/Editor/Config/Config.cs b/Editor/Config/Config.cs index 9c0adfe..4ab1ab2 100644 --- a/Editor/Config/Config.cs +++ b/Editor/Config/Config.cs @@ -113,7 +113,7 @@ public override void OnGUI() public class DefaultPMDImportConfig : ConfigBase { public PMDConverter.ShaderType shader_type = PMDConverter.ShaderType.MMDShader; - public bool use_mecanim = false; + public PMXConverter.AnimationType animation_type = PMXConverter.AnimationType.LegacyAnimation; public bool rigidFlag = true; public bool use_ik = true; public float scale = 0.085f; @@ -130,7 +130,7 @@ public override void OnGUI() { shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); - use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); // ここfalseになってたけど理由があるのかわからない + animation_type = (PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); use_ik = EditorGUILayout.Toggle("Use IK", use_ik); is_pmx_base_import = EditorGUILayout.Toggle("Use PMX Base Import", is_pmx_base_import); } diff --git a/Editor/Inspector/PMDInspector.cs b/Editor/Inspector/PMDInspector.cs index 2cd409a..6c6e375 100644 --- a/Editor/Inspector/PMDInspector.cs +++ b/Editor/Inspector/PMDInspector.cs @@ -12,7 +12,7 @@ public class PMDInspector : Editor // PMD Load option public PMDConverter.ShaderType shader_type; public bool rigidFlag; - public bool use_mecanim; + public PMXConverter.AnimationType animation_type; public bool use_ik; public float scale; public bool is_pmx_base_import; @@ -30,7 +30,7 @@ private void setup() var config = MMD.Config.LoadAndCreate(); shader_type = config.pmd_config.shader_type; rigidFlag = config.pmd_config.rigidFlag; - use_mecanim = config.pmd_config.use_mecanim; + animation_type = config.pmd_config.animation_type; use_ik = config.pmd_config.use_ik; scale = config.pmd_config.scale; is_pmx_base_import = config.pmd_config.is_pmx_base_import; @@ -64,7 +64,7 @@ public override void OnInspectorGUI() rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); // Mecanimを使うかどうか - use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); + animation_type = (PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); // IKを使うかどうか use_ik = EditorGUILayout.Toggle("Use IK", use_ik); @@ -100,7 +100,7 @@ public override void OnInspectorGUI() var obj = (PMDScriptableObject)target; model_agent = new ModelAgent(obj.assetPath); } - model_agent.CreatePrefab(shader_type, rigidFlag, use_mecanim, use_ik, scale, is_pmx_base_import); + model_agent.CreatePrefab(shader_type, rigidFlag, animation_type, use_ik, scale, is_pmx_base_import); message = "Loading done."; } } diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index 35862a9..61ade98 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -1,11 +1,11 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using UnityEditor; public class PMDLoaderWindow : EditorWindow { Object pmdFile = null; bool rigidFlag = true; - bool use_mecanim = false; + MMD.PMXConverter.AnimationType animation_type = MMD.PMXConverter.AnimationType.LegacyAnimation; MMD.PMDConverter.ShaderType shader_type = MMD.PMDConverter.ShaderType.MMDShader; bool use_ik = true; @@ -13,33 +13,33 @@ public class PMDLoaderWindow : EditorWindow { bool is_pmx_base_import = false; [MenuItem("MMD for Unity/PMD Loader")] - static void Init() { - var window = (PMDLoaderWindow)EditorWindow.GetWindow(true, "PMDLoader"); + static void Init() { + var window = (PMDLoaderWindow)EditorWindow.GetWindow(true, "PMDLoader"); window.Show(); } - public PMDLoaderWindow() - { - // デフォルトコンフィグ + public PMDLoaderWindow() + { + // デフォルトコンフィグ var config = MMD.Config.LoadAndCreate(); shader_type = config.pmd_config.shader_type; rigidFlag = config.pmd_config.rigidFlag; - use_mecanim = config.pmd_config.use_mecanim; + animation_type = config.pmd_config.animation_type; use_ik = config.pmd_config.use_ik; is_pmx_base_import = config.pmd_config.is_pmx_base_import; - } + } void OnGUI() { pmdFile = EditorGUILayout.ObjectField("PMD File" , pmdFile, typeof(Object), false); // シェーダの種類 - shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); + shader_type = (MMD.PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); // 剛体を入れるかどうか rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); - // Mecanimを使うかどうか - use_mecanim = EditorGUILayout.Toggle("Use Mecanim", use_mecanim); + // アニメーションタイプ + animation_type = (MMD.PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); // IKを使うかどうか use_ik = EditorGUILayout.Toggle("Use IK", use_ik); @@ -74,7 +74,7 @@ void OnGUI() { void LoadModel() { string file_path = AssetDatabase.GetAssetPath(pmdFile); MMD.ModelAgent model_agent = new MMD.ModelAgent(file_path); - model_agent.CreatePrefab(shader_type, rigidFlag, use_mecanim, use_ik, scale, is_pmx_base_import); + model_agent.CreatePrefab(shader_type, rigidFlag, animation_type, use_ik, scale, is_pmx_base_import); // 読み込み完了メッセージ var window = LoadedWindow.Init(); diff --git a/Editor/MMDLoader/Private/AvatarSettingScript.cs b/Editor/MMDLoader/Private/AvatarSettingScript.cs index 41b6729..3245dc1 100644 --- a/Editor/MMDLoader/Private/AvatarSettingScript.cs +++ b/Editor/MMDLoader/Private/AvatarSettingScript.cs @@ -18,15 +18,37 @@ public AvatarSettingScript(GameObject root_game_object, GameObject[] bones) { } /// - /// アバダーを設定する + /// 汎用アバダーを設定する + /// + /// アニメーター + public Animator SettingGenericAvatar() { + //アバタールートトランスフォームの取得 + Transform avatar_root_transform = root_game_object_.transform.FindChild("Model"); + if (null == avatar_root_transform) { + //ルートゲームオブジェクト直下にモデルルートオブジェクトが無い(PMDConverter)なら + //ルートゲームオブジェクトをアバタールートオブジェクトとする + avatar_root_transform = root_game_object_.transform; + } + + //ジェネリックアバター作成 + string root_name = ((HasBone("全ての親"))? "全ての親": ""); + avatar_ = AvatarBuilder.BuildGenericAvatar(avatar_root_transform.gameObject, root_name); + + //アバターをアニメーターに設定 + animator_ = root_game_object_.AddComponent(); + animator_.avatar = avatar_; + + return animator_; + } + + /// + /// 人型アバダーを設定する /// /// アニメーター - /// ルートゲームオブジェクト - /// ボーンのゲームオブジェクト /// /// モデルに依ってボーン構成に差が有るが、MMD標準モデルとの一致を優先する /// - public Animator SettingAvatar() { + public Animator SettingHumanAvatar() { //生成済みのボーンをUnity推奨ポーズに設定 SetRequirePose(); diff --git a/Editor/MMDLoader/Private/ModelAgent.cs b/Editor/MMDLoader/Private/ModelAgent.cs index 2e1be8b..cd721b4 100644 --- a/Editor/MMDLoader/Private/ModelAgent.cs +++ b/Editor/MMDLoader/Private/ModelAgent.cs @@ -32,11 +32,11 @@ public ModelAgent(string file_path) { /// /// シェーダーの種類 /// 剛体を使用するか - /// Mecanimを使用するか + /// アニメーションタイプ /// IKを使用するか /// スケール /// PMX Baseでインポートするか - public void CreatePrefab(PMDConverter.ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale, bool is_pmx_base_import) { + public void CreatePrefab(PMDConverter.ShaderType shader_type, bool use_rigidbody, PMXConverter.AnimationType animation_type, bool use_ik, float scale, bool is_pmx_base_import) { GameObject game_object; string prefab_path; if (is_pmx_base_import) { @@ -54,7 +54,7 @@ public void CreatePrefab(PMDConverter.ShaderType shader_type, bool use_rigidbody } header_ = pmx_format.header; //ゲームオブジェクトの作成 - game_object = PMXConverter.CreateGameObject(pmx_format, use_rigidbody, use_mecanim, use_ik, scale); + game_object = PMXConverter.CreateGameObject(pmx_format, use_rigidbody, animation_type, use_ik, scale); // プレファブパスの設定 prefab_path = pmx_format.meta_header.folder + "/" + pmx_format.meta_header.name + ".prefab"; @@ -74,6 +74,7 @@ public void CreatePrefab(PMDConverter.ShaderType shader_type, bool use_rigidbody header_ = PMXLoaderScript.PMD2PMX(pmd_format.head); //ゲームオブジェクトの作成 + bool use_mecanim = PMXConverter.AnimationType.LegacyAnimation == animation_type; game_object = PMDConverter.CreateGameObject(pmd_format, shader_type, use_rigidbody, use_mecanim, use_ik, scale); // プレファブパスの設定 diff --git a/Editor/MMDLoader/Private/PMDConverter.cs b/Editor/MMDLoader/Private/PMDConverter.cs index 2e27b90..58e46f5 100644 --- a/Editor/MMDLoader/Private/PMDConverter.cs +++ b/Editor/MMDLoader/Private/PMDConverter.cs @@ -89,7 +89,7 @@ private GameObject CreateGameObject_(PMDFormat format, ShaderType shader_type, b // Mecanim設定 if (use_mecanim_) { AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); - avatar_setting.SettingAvatar(); + avatar_setting.SettingHumanAvatar(); string path = format_.folder + "/"; string name = GetFilePathString(format_.name); diff --git a/Editor/MMDLoader/Private/PMXConverter.cs b/Editor/MMDLoader/Private/PMXConverter.cs index 77461e2..00c627f 100644 --- a/Editor/MMDLoader/Private/PMXConverter.cs +++ b/Editor/MMDLoader/Private/PMXConverter.cs @@ -8,18 +8,27 @@ namespace MMD { public class PMXConverter : System.IDisposable { + /// + /// アニメーションタイプ + /// + public enum AnimationType { + GenericMecanim, //汎用アバターでのMecanim + HumanMecanim, //人型アバターでのMecanim + LegacyAnimation, //旧式アニメーション + } + /// /// GameObjectを作成する /// /// 内部形式データ /// 剛体を使用するか - /// Mecanimを使用するか + /// アニメーションタイプ /// IKを使用するか /// スケール - public static GameObject CreateGameObject(PMXFormat format, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { + public static GameObject CreateGameObject(PMXFormat format, bool use_rigidbody, AnimationType animation_type, bool use_ik, float scale) { GameObject result; using (PMXConverter converter = new PMXConverter()) { - result = converter.CreateGameObject_(format, use_rigidbody, use_mecanim, use_ik, scale); + result = converter.CreateGameObject_(format, use_rigidbody, animation_type, use_ik, scale); } return result; } @@ -47,13 +56,11 @@ public void Dispose() /// /// 内部形式データ /// 剛体を使用するか - /// Mecanimを使用するか + /// アニメーションタイプ /// IKを使用するか /// スケール - private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale) { + private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, AnimationType animation_type, bool use_ik, float scale) { format_ = format; - use_rigidbody_ = use_rigidbody; - use_mecanim_ = use_mecanim; use_ik_ = use_ik; scale_ = scale; root_game_object_ = new GameObject(format_.meta_header.name); @@ -83,7 +90,7 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool } // 剛体関連 - if (use_rigidbody_) { + if (use_rigidbody) { GameObject[] rigids = CreateRigids(); AssignRigidbodyToBone(bones, rigids); SetRigidsSettings(bones, rigids); @@ -98,10 +105,19 @@ private GameObject CreateGameObject_(PMXFormat format, bool use_rigidbody, bool } // Mecanim設定 - if (use_mecanim_) { + if (AnimationType.LegacyAnimation != animation_type) { //アニメーター追加 AvatarSettingScript avatar_setting = new AvatarSettingScript(root_game_object_, bones); - avatar_setting.SettingAvatar(); + switch (animation_type) { + case AnimationType.GenericMecanim: //汎用アバターでのMecanim + avatar_setting.SettingGenericAvatar(); + break; + case AnimationType.HumanMecanim: //人型アバターでのMecanim + avatar_setting.SettingHumanAvatar(); + break; + default: + throw new System.ArgumentException(); + } string path = format_.meta_header.folder + "/"; string name = GetFilePathString(format_.meta_header.name); @@ -2020,8 +2036,6 @@ private static string GetFilePathString(string src) { GameObject root_game_object_; PMXFormat format_; - bool use_rigidbody_; - bool use_mecanim_; bool use_ik_; float scale_; AlphaReadableTexture alpha_readable_texture_ = null; diff --git a/Editor/MMDLoader/Private/VMDConverter.cs b/Editor/MMDLoader/Private/VMDConverter.cs index 53141cc..fbe78bc 100644 --- a/Editor/MMDLoader/Private/VMDConverter.cs +++ b/Editor/MMDLoader/Private/VMDConverter.cs @@ -53,6 +53,8 @@ private AnimationClip CreateAnimationClip_(MMD.VMD.VMDFormat format, GameObject CreateKeysForSkin(format, clip); // 表情の追加 + SetAnimationType(clip, assign_pmd); //アニメーションタイプの設定 + return clip; } @@ -535,6 +537,25 @@ void GetGameObjects(Dictionary obj, GameObject assign_pmd) } } + /// + /// アニメーションタイプの設定 + /// + /// 設定するアニメーションクリップ. + /// 設定の為に参照するAnimatorを持つゲームオブジェクト + static void SetAnimationType(AnimationClip clip, GameObject game_object) + { + ModelImporterAnimationType animation_type; + Animator animator = game_object.GetComponent(); + if (null == animator) { + animation_type = ModelImporterAnimationType.Legacy; + } else if ((null == animator.avatar) && animator.avatar.isHuman) { + animation_type = ModelImporterAnimationType.Human; + } else { + animation_type = ModelImporterAnimationType.Generic; + } + AnimationUtility.SetAnimationType(clip, animation_type); + } + private float scale_ = 1.0f; } } From 29143ce71757be0f46cc1e3c73c9874f67c9c51f Mon Sep 17 00:00:00 2001 From: "eral.r.l" Date: Mon, 13 Jan 2014 03:58:32 +0900 Subject: [PATCH 37/37] =?UTF-8?q?=E5=A4=89=E6=8F=9BUI=E5=91=A8=E3=82=8A?= =?UTF-8?q?=E3=81=AE=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Config/Config.cs | 167 +++++++++++++++++----------- Editor/Config/ConfigWindow.cs | 21 +--- Editor/Inspector/InspectorBase.cs | 50 +++++---- Editor/Inspector/PMDInspector.cs | 85 ++++---------- Editor/Inspector/VMDInspector.cs | 45 ++++---- Editor/MMDLoader/PMDLoaderWindow.cs | 67 ++++------- Editor/MMDLoader/VMDLoaderWindow.cs | 61 ++++------ 7 files changed, 217 insertions(+), 279 deletions(-) diff --git a/Editor/Config/Config.cs b/Editor/Config/Config.cs index 4ab1ab2..9539ad5 100644 --- a/Editor/Config/Config.cs +++ b/Editor/Config/Config.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; @@ -13,22 +13,26 @@ namespace MMD [Serializable] public class Config : ScriptableObject { - public InspectorConfig inspector_config; - public DefaultPMDImportConfig pmd_config; - public DefaultVMDImportConfig vmd_config; + static Config config_ = null; + public InspectorConfig inspector_config = null; + public PMDImportConfig pmd_config = null; + public VMDImportConfig vmd_config = null; - private List update_list; + private List update_list = null; public void OnEnable() { - // Inspectorで編集をさせない - hideFlags = HideFlags.NotEditable; - if (pmd_config == null) + if (inspector_config == null) { - // ここで初期化処理を書く - pmd_config = new DefaultPMDImportConfig(); - vmd_config = new DefaultVMDImportConfig(); inspector_config = new InspectorConfig(); } + if (pmd_config == null) + { + pmd_config = new PMDImportConfig(); + } + if (vmd_config == null) + { + vmd_config = new VMDImportConfig(); + } if (update_list == null) { update_list = new List(); @@ -36,6 +40,8 @@ public void OnEnable() update_list.Add(pmd_config); update_list.Add(vmd_config); } + + hideFlags = HideFlags.None; //以前の書き換え不可assetが残っているかもしれないので明示的に書き換え可能を設定 } /// @@ -48,6 +54,11 @@ public void OnGUI() { item.OnGUI(); }); + + //変更確認 + if (GUI.changed) { + EditorUtility.SetDirty(config_); + } } /// @@ -67,17 +78,20 @@ public static string GetConfigPath() /// 読み込んで生成したConfigオブジェクト public static Config LoadAndCreate() { - var path = Config.GetConfigPath(); - var config = (Config)AssetDatabase.LoadAssetAtPath(path, typeof(Config)); - - //// なかったら作成する - if (config == null) + if (config_ == null) { - config = CreateInstance(); - AssetDatabase.CreateAsset(config, path); - EditorUtility.SetDirty(config); + var path = Config.GetConfigPath(); + config_ = (Config)AssetDatabase.LoadAssetAtPath(path, typeof(Config)); + + //// なかったら作成する + if (config_ == null) + { + config_ = CreateInstance(); + AssetDatabase.CreateAsset(config_, path); + EditorUtility.SetDirty(config_); + } } - return config; + return config_; } } @@ -87,79 +101,94 @@ public static Config LoadAndCreate() [Serializable] public class InspectorConfig : ConfigBase { - public bool use_pmd_preload = false; - public bool use_vmd_preload = false; + public bool use_pmd_preload = true; + public bool use_vmd_preload = true; - public InspectorConfig() + public override string GetTitle() { - this.title = "Inspector Config"; + return "Inspector Config"; } - public override void OnGUI() + public override void OnGUIFunction() { - base.OnGUI(() => - { - use_pmd_preload = EditorGUILayout.Toggle("Use PMD Preload", use_pmd_preload); - use_vmd_preload = EditorGUILayout.Toggle("Use VMD Preload", use_vmd_preload); - } - ); + use_pmd_preload = EditorGUILayout.Toggle("Use PMD Preload", use_pmd_preload); + use_vmd_preload = EditorGUILayout.Toggle("Use VMD Preload", use_vmd_preload); + } + + public InspectorConfig Clone() + { + return (InspectorConfig)MemberwiseClone(); } } /// - /// PMDインポートのデフォルトコンフィグ + /// PMDインポートのコンフィグ /// [Serializable] - public class DefaultPMDImportConfig : ConfigBase + public class PMDImportConfig : ConfigBase { public PMDConverter.ShaderType shader_type = PMDConverter.ShaderType.MMDShader; public PMXConverter.AnimationType animation_type = PMXConverter.AnimationType.LegacyAnimation; public bool rigidFlag = true; public bool use_ik = true; public float scale = 0.085f; - public bool is_pmx_base_import = false; + public bool is_pmx_base_import = true; - public DefaultPMDImportConfig() + public override string GetTitle() { - this.title = "Default PMD Import Config"; + return "Default PMD Import Config"; } - public override void OnGUI() + public override void OnGUIFunction() { - base.OnGUI(() => - { - shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); - rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); - animation_type = (PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); - use_ik = EditorGUILayout.Toggle("Use IK", use_ik); - is_pmx_base_import = EditorGUILayout.Toggle("Use PMX Base Import", is_pmx_base_import); + shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); + rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); + animation_type = (PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); + use_ik = EditorGUILayout.Toggle("Use IK", use_ik); + scale = EditorGUILayout.Slider("Scale", scale, 0.001f, 1.0f); + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.PrefixLabel(" "); + if (GUILayout.Button("Original", EditorStyles.miniButtonLeft)) { + scale = 0.085f; + } + if (GUILayout.Button("1.0", EditorStyles.miniButtonRight)) { + scale = 1.0f; } - ); + } + EditorGUILayout.EndHorizontal(); + is_pmx_base_import = EditorGUILayout.Toggle("Use PMX Base Import", is_pmx_base_import); + } + + public PMDImportConfig Clone() + { + return (PMDImportConfig)MemberwiseClone(); } } /// - /// VMDインポートのデフォルトコンフィグ + /// VMDインポートのコンフィグ /// [Serializable] - public class DefaultVMDImportConfig : ConfigBase + public class VMDImportConfig : ConfigBase { - public bool createAnimationFile; - public int interpolationQuality; + public bool createAnimationFile = false; + public int interpolationQuality = 1; - public DefaultVMDImportConfig() + public override string GetTitle() { - this.title = "Default VMD Import Config"; + return "Default VMD Import Config"; } - public override void OnGUI() + public override void OnGUIFunction() { - base.OnGUI(() => - { - createAnimationFile = EditorGUILayout.Toggle("Create Asset", createAnimationFile); - interpolationQuality = EditorGUILayout.IntSlider("Interpolation Quality", interpolationQuality, 1, 10); - } - ); + createAnimationFile = EditorGUILayout.Toggle("Create Asset", createAnimationFile); + interpolationQuality = EditorGUILayout.IntSlider("Interpolation Quality", interpolationQuality, 1, 10); + } + + public VMDImportConfig Clone() + { + return (VMDImportConfig)MemberwiseClone(); } } @@ -168,11 +197,6 @@ public override void OnGUI() /// public class ConfigBase { - /// - /// このコンフィグのタイトルを指定します - /// - protected string title = ""; - /// /// 開け閉めの状態 /// @@ -181,19 +205,28 @@ public class ConfigBase /// /// GUI処理を行います /// - /// 引数・戻り値なしのラムダ式 - public void OnGUI(Action OnGUIFunction) + public void OnGUI() { + var title = GetTitle(); fold = EditorGUILayout.Foldout(fold, title); - if (fold) + if (fold) { OnGUIFunction(); + } EditorGUILayout.Space(); } + /// + /// このコンフィグのタイトルを取得します + /// + public virtual string GetTitle() + { + return ""; + } + /// /// GUI処理を行います /// - public virtual void OnGUI() + public virtual void OnGUIFunction() { } } diff --git a/Editor/Config/ConfigWindow.cs b/Editor/Config/ConfigWindow.cs index 08fa9b3..c4dc2a7 100644 --- a/Editor/Config/ConfigWindow.cs +++ b/Editor/Config/ConfigWindow.cs @@ -5,8 +5,7 @@ namespace MMD { public class ConfigWindow : EditorWindow { - private static Config config; - private static string path; + private Config config; [MenuItem("MMD for Unity/Config")] public static void Init() @@ -18,36 +17,18 @@ public static void Init() // フォーカスが外れて戻ってきたときや再度開かれたときなど void OnEnable() { - // オブジェクトを「Hierarchy」に表示しない。また、アセットの中にあれば、プロジェクトビューに表示しない - // オブジェクトがシーンに保存されない。また、新しいシーンを読んでも、オブジェクトが破棄されない - hideFlags = HideFlags.HideAndDontSave; - if (config == null) { // 読み込む config = MMD.Config.LoadAndCreate(); - - // なかったら作成する - if (config == null) - { - path = MMD.Config.GetConfigPath(); - config = CreateInstance(); - AssetDatabase.CreateAsset(config, path); - EditorUtility.SetDirty(config); - } } } // ウィンドウの描画処理 void OnGUI() { - // たいとる - EditorGUILayout.LabelField("MMD for Unity Configuration"); - EditorGUILayout.Space(); - // あとは任せる config.OnGUI(); - } } } diff --git a/Editor/Inspector/InspectorBase.cs b/Editor/Inspector/InspectorBase.cs index 7bad797..6303379 100644 --- a/Editor/Inspector/InspectorBase.cs +++ b/Editor/Inspector/InspectorBase.cs @@ -12,32 +12,43 @@ using UnityEditor.Callbacks; using UnityEngine; -#if !(UNITY_3_5 || UNITY_3_4 || UNITY_3_3) - namespace MMD { - public class InspectorBase : Editor - { + [InitializeOnLoad] + public class InspectorBase : Editor + { + static InspectorBase() + { + EntryEditorApplicationUpdate(); + } + [DidReloadScripts] static void OnDidReloadScripts() { - EditorApplication.update += () => + EntryEditorApplicationUpdate(); + } + + static void EntryEditorApplicationUpdate() + { + EditorApplication.update += Update; + } + + static void Update() + { + if (Selection.objects.Length != 0) { - if (Selection.objects.Length != 0) + string path = AssetDatabase.GetAssetPath(Selection.activeObject); + string extension = Path.GetExtension(path).ToLower(); + + if (extension == ".pmd" || extension == ".pmx") + { + SetupScriptableObject(path); + } + else if (extension == ".vmd") { - string path = AssetDatabase.GetAssetPath(Selection.activeObject); - string extension = Path.GetExtension(path).ToLower(); - - if (extension == ".pmd" || extension == ".pmx") - { - SetupScriptableObject(path); - } - else if (extension == ".vmd") - { - SetupScriptableObject(path); - } + SetupScriptableObject(path); } - }; + } } static void SetupScriptableObject(string path) where T : ScriptableObjectBase @@ -49,8 +60,7 @@ static void SetupScriptableObject(string path) where T : ScriptableObjectBase Selection.activeObject = scriptableObject; EditorUtility.UnloadUnusedAssets(); } - } + } } #endif -#endif \ No newline at end of file diff --git a/Editor/Inspector/PMDInspector.cs b/Editor/Inspector/PMDInspector.cs index 6c6e375..5eda14b 100644 --- a/Editor/Inspector/PMDInspector.cs +++ b/Editor/Inspector/PMDInspector.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using UnityEditor; using System.Collections; using MMD.PMD; @@ -6,40 +6,29 @@ namespace MMD { - [CustomEditor(typeof(PMDScriptableObject))] + [CustomEditor(typeof(PMDScriptableObject))] public class PMDInspector : Editor { - // PMD Load option - public PMDConverter.ShaderType shader_type; - public bool rigidFlag; - public PMXConverter.AnimationType animation_type; - public bool use_ik; - public float scale; - public bool is_pmx_base_import; + PMDImportConfig pmd_config; // last selected item - private static ModelAgent model_agent; - private static string message = ""; + private ModelAgent model_agent; + private string message = ""; /// - /// pmd_headerとデフォルトコンフィグの設定 + /// 有効化処理 /// - private void setup() + private void OnEnable() { // デフォルトコンフィグ - var config = MMD.Config.LoadAndCreate(); - shader_type = config.pmd_config.shader_type; - rigidFlag = config.pmd_config.rigidFlag; - animation_type = config.pmd_config.animation_type; - use_ik = config.pmd_config.use_ik; - scale = config.pmd_config.scale; - is_pmx_base_import = config.pmd_config.is_pmx_base_import; - + var config = MMD.Config.LoadAndCreate(); + pmd_config = config.pmd_config.Clone(); + // モデル情報 if (config.inspector_config.use_pmd_preload) { - var obj = (PMDScriptableObject)target; - model_agent = new ModelAgent(obj.assetPath); + var obj = (PMDScriptableObject)target; + model_agent = new ModelAgent(obj.assetPath); } else { @@ -52,39 +41,11 @@ private void setup() /// public override void OnInspectorGUI() { - setup(); - // GUIの有効化 GUI.enabled = !EditorApplication.isPlaying; - // シェーダの種類 - shader_type = (PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); - - // 剛体を入れるかどうか - rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); - - // Mecanimを使うかどうか - animation_type = (PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); - - // IKを使うかどうか - use_ik = EditorGUILayout.Toggle("Use IK", use_ik); - - // スケール - scale = EditorGUILayout.Slider("Scale", scale, 0.001f, 1.0f); - EditorGUILayout.BeginHorizontal(); - { - EditorGUILayout.PrefixLabel(" "); - if (GUILayout.Button("0.085", EditorStyles.miniButtonLeft)) { - scale = 0.085f; - } - if (GUILayout.Button("1.0", EditorStyles.miniButtonRight)) { - scale = 1.0f; - } - } - EditorGUILayout.EndHorizontal(); - - // PMX Baseでインポートするかどうか - is_pmx_base_import = EditorGUILayout.Toggle("Use PMX Base Import", is_pmx_base_import); + // GUI描画 + pmd_config.OnGUIFunction(); // Convertボタン EditorGUILayout.Space(); @@ -97,10 +58,16 @@ public override void OnInspectorGUI() if (GUILayout.Button("Convert to Prefab")) { if (null == model_agent) { - var obj = (PMDScriptableObject)target; + var obj = (PMDScriptableObject)target; model_agent = new ModelAgent(obj.assetPath); } - model_agent.CreatePrefab(shader_type, rigidFlag, animation_type, use_ik, scale, is_pmx_base_import); + model_agent.CreatePrefab(pmd_config.shader_type + , pmd_config.rigidFlag + , pmd_config.animation_type + , pmd_config.use_ik + , pmd_config.scale + , pmd_config.is_pmx_base_import + ); message = "Loading done."; } } @@ -109,16 +76,12 @@ public override void OnInspectorGUI() // モデル情報 if (model_agent == null) return; EditorGUILayout.LabelField("Model Name"); - GUI.enabled = false; - EditorGUILayout.TextArea(model_agent.name); - GUI.enabled = true; + EditorGUILayout.LabelField(model_agent.name, EditorStyles.textField); EditorGUILayout.Space(); EditorGUILayout.LabelField("Comment"); - GUI.enabled = false; - EditorGUILayout.TextArea(model_agent.comment, GUILayout.Height(300)); - GUI.enabled = true; + EditorGUILayout.LabelField(model_agent.comment, EditorStyles.textField, GUILayout.Height(300)); } } } diff --git a/Editor/Inspector/VMDInspector.cs b/Editor/Inspector/VMDInspector.cs index c4aa480..e564939 100644 --- a/Editor/Inspector/VMDInspector.cs +++ b/Editor/Inspector/VMDInspector.cs @@ -4,37 +4,32 @@ using MMD.PMD; using System.IO; -#if !(UNITY_3_5 || UNITY_3_4 || UNITY_3_3) - namespace MMD { - [CustomEditor(typeof(VMDScriptableObject))] + [CustomEditor(typeof(VMDScriptableObject))] public class VMDInspector : Editor { // VMD Load option - public bool createAnimationFile; - public int interpolationQuality; public GameObject pmdPrefab; + VMDImportConfig vmd_config; // last selected item - private static MotionAgent motion_agent; - private static string message = ""; + private MotionAgent motion_agent; + private string message = ""; /// - /// 選択されているオブジェクトがVMDファイルかチェックします + /// 有効化処理 /// - /// VMDファイルであればそのパスを、異なればnullを返します。 - void setup() + void OnEnable() { // デフォルトコンフィグ var config = MMD.Config.LoadAndCreate(); - createAnimationFile = config.vmd_config.createAnimationFile; - interpolationQuality = config.vmd_config.interpolationQuality; + vmd_config = config.vmd_config.Clone(); // モデル情報 if (config.inspector_config.use_vmd_preload) { - var obj = (VMDScriptableObject)target; + var obj = (VMDScriptableObject)target; motion_agent = new MotionAgent(obj.assetPath); } else @@ -48,14 +43,11 @@ void setup() /// public override void OnInspectorGUI() { - setup(); - // GUIの有効化 - GUI.enabled = true; + GUI.enabled = !EditorApplication.isPlaying; - pmdPrefab = EditorGUILayout.ObjectField("PMD Prefab", pmdPrefab, typeof(Object), false) as GameObject; - createAnimationFile = EditorGUILayout.Toggle("Create Asset", createAnimationFile); - interpolationQuality = EditorGUILayout.IntSlider("Interpolation Quality", interpolationQuality, 1, 10); + pmdPrefab = (GameObject)EditorGUILayout.ObjectField("PMD Prefab", pmdPrefab, typeof(Object), false); + vmd_config.OnGUIFunction(); // Convertボタン EditorGUILayout.Space(); @@ -65,25 +57,28 @@ public override void OnInspectorGUI() } else { + bool gui_enabled_old = GUI.enabled; + GUI.enabled = (null != pmdPrefab); if (GUILayout.Button("Convert")) { if (null == motion_agent) { - var obj = (VMDScriptableObject)target; + var obj = (VMDScriptableObject)target; motion_agent = new MotionAgent(obj.assetPath); } - motion_agent.CreateAnimationClip(pmdPrefab, createAnimationFile, interpolationQuality); + motion_agent.CreateAnimationClip(pmdPrefab + , vmd_config.createAnimationFile + , vmd_config.interpolationQuality + ); message = "Loading done."; } + GUI.enabled = gui_enabled_old; } GUILayout.Space(40); // モデル情報 if (motion_agent == null) return; EditorGUILayout.LabelField("Model Name"); - GUI.enabled = false; - EditorGUILayout.TextArea(motion_agent.model_name); - GUI.enabled = true; + EditorGUILayout.LabelField(motion_agent.model_name, EditorStyles.textField); } } } -#endif \ No newline at end of file diff --git a/Editor/MMDLoader/PMDLoaderWindow.cs b/Editor/MMDLoader/PMDLoaderWindow.cs index 61ade98..cc13aa7 100644 --- a/Editor/MMDLoader/PMDLoaderWindow.cs +++ b/Editor/MMDLoader/PMDLoaderWindow.cs @@ -3,14 +3,8 @@ using UnityEditor; public class PMDLoaderWindow : EditorWindow { - Object pmdFile = null; - bool rigidFlag = true; - MMD.PMXConverter.AnimationType animation_type = MMD.PMXConverter.AnimationType.LegacyAnimation; - MMD.PMDConverter.ShaderType shader_type = MMD.PMDConverter.ShaderType.MMDShader; - - bool use_ik = true; - float scale = 0.085f; - bool is_pmx_base_import = false; + Object pmdFile; + MMD.PMDImportConfig pmd_config; [MenuItem("MMD for Unity/PMD Loader")] static void Init() { @@ -18,63 +12,42 @@ static void Init() { window.Show(); } - public PMDLoaderWindow() + void OnEnable() { // デフォルトコンフィグ - var config = MMD.Config.LoadAndCreate(); - shader_type = config.pmd_config.shader_type; - rigidFlag = config.pmd_config.rigidFlag; - animation_type = config.pmd_config.animation_type; - use_ik = config.pmd_config.use_ik; - is_pmx_base_import = config.pmd_config.is_pmx_base_import; + pmdFile = null; + pmd_config = MMD.Config.LoadAndCreate().pmd_config.Clone(); } void OnGUI() { + // GUIの有効化 + GUI.enabled = !EditorApplication.isPlaying; + + // GUI描画 pmdFile = EditorGUILayout.ObjectField("PMD File" , pmdFile, typeof(Object), false); + pmd_config.OnGUIFunction(); - // シェーダの種類 - shader_type = (MMD.PMDConverter.ShaderType)EditorGUILayout.EnumPopup("Shader Type", shader_type); - - // 剛体を入れるかどうか - rigidFlag = EditorGUILayout.Toggle("Rigidbody", rigidFlag); - - // アニメーションタイプ - animation_type = (MMD.PMXConverter.AnimationType)EditorGUILayout.EnumPopup("Animation Type", animation_type); - - // IKを使うかどうか - use_ik = EditorGUILayout.Toggle("Use IK", use_ik); - - // スケール - scale = EditorGUILayout.Slider("Scale", scale, 0.001f, 1.0f); - EditorGUILayout.BeginHorizontal(); { - EditorGUILayout.PrefixLabel(" "); - if (GUILayout.Button("Original", EditorStyles.miniButtonLeft)) { - scale = 0.085f; - } - if (GUILayout.Button("1.0", EditorStyles.miniButtonRight)) { - scale = 1.0f; - } - } - EditorGUILayout.EndHorizontal(); - - // PMX Baseでインポートするかどうか - is_pmx_base_import = EditorGUILayout.Toggle("Use PMX Base Import", is_pmx_base_import); - - if (pmdFile != null) { + bool gui_enabled_old = GUI.enabled; + GUI.enabled = !EditorApplication.isPlaying && (pmdFile != null); if (GUILayout.Button("Convert")) { LoadModel(); pmdFile = null; // 読み終わったので空にする } - } else { - EditorGUILayout.LabelField("Missing", "Select PMD File"); + GUI.enabled = gui_enabled_old; } } void LoadModel() { string file_path = AssetDatabase.GetAssetPath(pmdFile); MMD.ModelAgent model_agent = new MMD.ModelAgent(file_path); - model_agent.CreatePrefab(shader_type, rigidFlag, animation_type, use_ik, scale, is_pmx_base_import); + model_agent.CreatePrefab(pmd_config.shader_type + , pmd_config.rigidFlag + , pmd_config.animation_type + , pmd_config.use_ik + , pmd_config.scale + , pmd_config.is_pmx_base_import + ); // 読み込み完了メッセージ var window = LoadedWindow.Init(); diff --git a/Editor/MMDLoader/VMDLoaderWindow.cs b/Editor/MMDLoader/VMDLoaderWindow.cs index 56dca50..c038c07 100644 --- a/Editor/MMDLoader/VMDLoaderWindow.cs +++ b/Editor/MMDLoader/VMDLoaderWindow.cs @@ -5,8 +5,7 @@ public class VMDLoaderWindow : EditorWindow { Object vmdFile; GameObject pmdPrefab; - bool createAnimationFile; - int interpolationQuality; + MMD.VMDImportConfig vmd_config; [MenuItem ("MMD for Unity/VMD Loader")] static void Init() { @@ -14,56 +13,40 @@ static void Init() { window.Show(); } - public VMDLoaderWindow() - { - // デフォルトコンフィグ - var config = MMD.Config.LoadAndCreate(); - createAnimationFile = config.vmd_config.createAnimationFile; - interpolationQuality = config.vmd_config.interpolationQuality; - } + void OnEnable() + { + // デフォルトコンフィグ + vmdFile = null; + pmdPrefab = null; + vmd_config = MMD.Config.LoadAndCreate().vmd_config.Clone(); + } void OnGUI() { - const int height = 20; - int top = 0; - - pmdPrefab = EditorGUI.ObjectField( - new Rect(0, top, position.width - 16, height), "PMD Prefab", pmdPrefab, typeof(GameObject), false) as GameObject; - top += height + 2; - - vmdFile = EditorGUI.ObjectField( - new Rect(0, top, position.width - 16, height), "VMD File", vmdFile, typeof(Object), false); - top += height + 2; + // GUIの有効化 + GUI.enabled = !EditorApplication.isPlaying; - createAnimationFile = EditorGUI.Toggle( - new Rect(0, top, position.width - 16, height), "Create Asset", createAnimationFile); - top += height + 2; + // GUI描画 + pmdPrefab = (GameObject)EditorGUILayout.ObjectField("PMD Prefab", pmdPrefab, typeof(GameObject), false); + vmdFile = EditorGUILayout.ObjectField("VMD File", vmdFile, typeof(Object), false); + vmd_config.OnGUIFunction(); - interpolationQuality=EditorGUI.IntSlider ( - new Rect(0, top, position.width - 16, height), "Interpolation Quality", interpolationQuality, 1, 10); - top += height + 2; - - if (pmdPrefab != null && vmdFile != null) { - if (GUI.Button(new Rect(0, top, position.width / 2, 16), "Convert")) - { + bool gui_enabled_old = GUI.enabled; + GUI.enabled = !EditorApplication.isPlaying && (pmdPrefab != null) && (vmdFile != null); + if (GUILayout.Button("Convert")) { LoadMotion(); vmdFile = null; } - } - else - { - if (pmdPrefab == null) - EditorGUI.LabelField(new Rect(0, top, position.width, height), "Missing", "Select PMD Prefab"); - else if (vmdFile == null) - EditorGUI.LabelField(new Rect(0, top, position.width, height), "Missing", "Select VMD File"); - else - EditorGUI.LabelField(new Rect(0, top, position.width, height), "Missing", "Select PMD and VMD"); + GUI.enabled = gui_enabled_old; } } void LoadMotion() { string file_path = AssetDatabase.GetAssetPath(vmdFile); MMD.MotionAgent motion_agent = new MMD.MotionAgent(file_path); - motion_agent.CreateAnimationClip(pmdPrefab, createAnimationFile,interpolationQuality); + motion_agent.CreateAnimationClip(pmdPrefab + , vmd_config.createAnimationFile + , vmd_config.interpolationQuality + ); } }